老派排字员从来不会允许段落的最后一行几乎填充。要么它会明显比其他线条短,要么它会被拉伸以与右边距对齐。(我认为他们决定拉伸线条的标准值是缩进的深度。)
如果您有时间,可以通过检查所有页面并手动添加\parfillskip=0pt
所有违规段落来获得相同的结果。
例如本文档:
\documentclass{article}
\usepackage[paperwidth=3in,paperheight=3in]{geometry}
\begin{document}
\thispagestyle{empty}
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
sasdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdfxx
\end{document}
渲染为最后一行几乎完整的段落:
我之前曾被告知,pdfLaTeX 自动执行此操作很可能是不可能的。
如果这是真的——可以用 LuaTeX 来实现吗?
答案1
这可以在 LuaTeX 中使用回调来完成pre_linebreak_filter
:在“正常”换行之前,进行“试验性”换行并测量有效填充。如果它低于当前的值\parindent
,则将此段落的填充设置为零。此外,有时可能会发生\parfillskip=0pt
失败的情况。在这种情况下,这将拉伸最后一行而不影响其余段落,从而导致行可能非常拉伸。如果您在这种情况下只想接受几乎填充的行,只需删除被包围的部分即可
luatexbase.add_to_callback("post_linebreak_filter", function(head)
...
end, "drop_short_parfill")
\documentclass{article}
\usepackage[paperwidth=3in,paperheight=3in]{geometry}
\usepackage{luacode}
\begin{luacode*}
local glue = node.id'glue'
luatexbase.add_to_callback("pre_linebreak_filter", function(head)
local copy = node.copy_list(head)
local parfill = node.tail(copy)
if not parfill.id == glue or not parfill.subtype == 15 then
texio.write_nl'Unable to find the parfill. Disabling special handler.'
node.flush_list(copy)
return true
end
local lines, infos = tex.linebreak(copy)
local last = node.tail(lines)
if tex.parindent > node.effective_glue(parfill, last) then
node.flush_list(lines)
copy = node.copy_list(head)
parfill = node.tail(copy)
node.setglue(parfill)
lines, infos = tex.linebreak(copy)
local t = node.tail(lines)
if t.width == node.rangedimensions(t, t.head) then
parfill = node.tail(head)
node.setglue(parfill)
end
end
node.flush_list(lines)
return true
end, "drop_short_parfill")
luatexbase.add_to_callback("post_linebreak_filter", function(head)
local t = node.tail(head)
local tt = node.slide(t.head)
while tt.id ~= glue or tt.subtype ~= 15 do
tt = tt.prev
end
if tex.parindent > node.effective_glue(tt, t) then
node.setglue(tt)
local n = node.hpack(t.head, t.width, "exactly")
head = node.insert_before(head, t, n)
n.next, t.head = nil, nil
node.free(t)
end
return head
end, "drop_short_parfill")
\end{luacode*}
\begin{document}
\thispagestyle{empty}
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
sasdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
sasdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdfx
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
sasdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdfxx
\end{document}
在本例中,第一段无需任何更改。第三段会自动拉伸\parfillskip=0pt
,而第二段仅拉伸最后一行。
如果你想知道为什么“试验”换行的结果总是被丢弃而不是被重新用作实际的换行符,特别是如果不需要进行任何更改:这将通过 来实现linebreak_filter
,但这在当前的 LuaTeX 版本中已被破坏。
答案2
添加\parfillskip
具有最小长度和无限可拉伸性的似乎可以做到这一点。
例如,以下设置parfillskip
使得段落末尾必须至少有等于最少 2 个x
字符的空格:
\documentclass{article}
\usepackage[paperwidth=3in,paperheight=3in]{geometry}
\begin{document}
\thispagestyle{empty}
%% Measure the width of 'x' in this font
%% and set \parfillskip equal to two times
%% that width.
\setbox0=\hbox{x} \parfillskip=2\wd0 plus1fil
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
sasdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdfxx
\end{document}
注释掉该\parfillskip=2\wd0 plus1fil
行会得到:
parfillskip
但是设置后会显示以下内容:
答案3
我不确定我是否认真,但如果你能够(或愿意)通过先收集段落来重新排版它们,那么 TeX 的一个功能可以让你测量并采取行动:如果段落(或准确地说是部分段落)的最后一行后面跟着数学显示,TeX 就会知道它的长度。在这种情况下,显示上方的行的长度在公式中为\predisplaysize
。因此你可以
- 在宏中收集段落材料,比如
- 试排版一下,看看最后一行和整行有多接近
- 根据结果,使用合适的值认真重新排版段落
\parfillskip
,例如,将其设置为0pt
或将其设置为2em plus 1fil
或其他。
以下是检查代码:
\newdimen\mydim
\def\checkit{%
\mydim\hsize
\advance\mydim by -\predisplaysize
\advance\mydim by 2em
\typeout{There is \the\mydim\space space available on the last line}%
}
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdf sadf
asdfjk adsf af dsasdf f dasf fdsa fds afsd fdsaf asdfsdafdsa asdf dsaf asdfxx
$$\checkit$$
减去是2em
因为\predisplaysize
是最后一行的长度 + 2em。对于您的示例,我们得到:
There is 4.98819pt space available on the last line
有一些特殊情况:如果最后一行不是按照其自然宽度排版,那么给出的大小\maxdimen
,例如,如果\parfillskip
设置为 0pt,并且如果没有前一行,那么它将设置为,-\maxdimen
但这两种情况都可以根据您的情况进行控制。