使用 LuaLaTeX 自动改变字母间距(单词内间距)以避免出现松散的线条

使用 LuaLaTeX 自动改变字母间距(单词内间距)以避免出现松散的线条

在 James Felici 的书中The Complete Manual of Typography,建议有时改变字母之间的间距,以免单词之间的间距过大。

在此处输入图片描述

我尝试使用Trackingfrommicrotype包,但只能将其设置为常量值。LetterSpace中也有选项fontspec,但似乎效果差不多。

这可以在 完成吗LuaLaTeX

\documentclass{article}

\usepackage{lipsum}

\usepackage{fontspec}

\usepackage[
        expansion   =   false,
        tracking    =   alltext,
    ]{microtype}

\SetTracking{
    family  =   *}{10} 

\begin{document}

    \lipsum

\end{document}

答案1

虽然印刷师们对此有不同的看法关于字母间距,当在窄列中设置对齐文本时,我们必须在某些地方做出一些妥协(包括考虑右对齐文本),字母间距似乎是可以接受的。因此,我很震惊该microtype软件包似乎没有提供此功能;毕竟它在 Hàn Thế Thành 的论文中被广泛讨论过TeX 排版系统的微排版扩展microtype。尽管我为了这个功能查看了好几次,但我仍然不确定我是否只是错过了文档中的某些内容。

无论如何,使用 LuaTeX 可以轻松实现这一点。有多种方法:例如,在换行之后(在 中post_linebreak_filter),我们可以在节点之间添加适当的拉伸量(这是 Hàn Thế Thành 论文第 6.8 节中讨论的方法)。或者,在换行之前(在 中pre_linebreak_filter),我们可以添加可拉伸的粘合节点。第二种方法在包中实现chickenize,即\letterspaceadjust。它只有几行代码,因此我们可以复制它并根据需要进行更改(在下面的代码示例中,我仅将letterspace_glue.stretch0.5 pt 更改为 10pt)。

输出

\documentclass{article}
\usepackage{lipsum}
\usepackage{fontspec}
\usepackage{luacode}

\usepackage{chickenize}

\begin{document}
\hsize=15em
\frenchspacing
\def\\{\penalty-10000}
\def\sample{
The results of the first round of\\
the elections shook the public\\
rigid, as it seemed impossible\\
that a candidate from the far\\
right wing---who indeed had\\
been a Nazi Party member dur-\\
ing his youth---ousted the cen-\\
ter-left candidate. The outcry\\
from the general public was\\
considerable but also considera-\\
bly too late. The run-up to the\\
election had been somnolent---and\\
people learned too late that the\\
unimaginable only seems that\\
way when people fail to use\\
their imagination.}

\noindent The default:

\sample

\lipsum[1]


\newpage
\noindent Best result without letter spacing:
\tolerance=9999 \hfuzz=0.1pt \emergencystretch=\hsize

\sample

\lipsum[1]

\newpage
\noindent With letter spacing:
\letterspaceadjust

\sample

\lipsum[1]

\newpage
\noindent Exaggerated letter spacing:
\unletterspaceadjust
\begin{luacode}
local nodeid   = node.id
local nodenew  = node.new
local nodecopy = node.copy
local nodetraverseid = node.traverse_id
local nodeinsertbefore = node.insert_before

local letterspace_glue   = nodenew(nodeid"glue")
local letterspace_pen    = nodenew(nodeid"penalty")
letterspace_glue.width   = tex.sp"0pt"
letterspace_glue.stretch = tex.sp"10pt"
letterspace_pen.penalty  = 10000
letterspaceadjust = function(head)
  for glyph in nodetraverseid(nodeid"glyph", head) do
    if glyph.prev and (glyph.prev.id == nodeid"glyph" or glyph.prev.id == nodeid"disc" or glyph.prev.id == nodeid"kern") then
      local g = nodecopy(letterspace_glue)
      nodeinsertbefore(head, glyph, g)
      nodeinsertbefore(head, g, nodecopy(letterspace_pen))
    end
  end
  return head
end
luatexbase.add_to_callback("pre_linebreak_filter",letterspaceadjust,"letterspaceadjust")
\end{luacode}

\sample

\lipsum[1]

\end{document}

为了清楚起见,这里再次列出相关代码,无需从包中加载。将以下内容放入名为的文件中letterspacing.lua

local interletter_glue   = node.new('glue')
interletter_glue.width   = tex.sp(0)
interletter_glue.stretch = tex.sp('0.5 pt') -- This number controls how much the space between letters can stretch.
local interletter_pen    = node.new('penalty')
interletter_pen.penalty  = 10000

add_interletter_glue = function(head)
   -- Adds equivalent of "\penalty10000\hskip 0pt plus 0.5pt" (the above penalty and glue)
   -- before every letter (glyph) that follows a glyph, discretionary (hyphen), or kern node.
   for glyph in node.traverse_id(node.id('glyph'), head) do
      if glyph.prev and (glyph.prev.id == node.id('glyph') or
                         glyph.prev.id == node.id('disc') or
                         glyph.prev.id == node.id('kern')) then
         local g = node.copy(interletter_glue)
         node.insert_before(head, glyph, g)
         node.insert_before(head, g, node.copy(interletter_pen))
      end
   end
   return head
end
luatexbase.add_to_callback("pre_linebreak_filter", add_interletter_glue, "Allow variable interletter spacing.")

现在,您可以使用以下方式排版文件lualatex

\documentclass{article}
\usepackage{lipsum}                                            % For random text
\begin{document}
\hsize=10em \frenchspacing              % Just to make the effects easier to see
\tolerance=9999 \emergencystretch=\maxdimen  % Work harder, avoid overfull boxes

\lipsum                                 % This is typeset without letter-spacing

\directlua{dofile('letterspacing.lua')}                 % Turn on letter-spacing

\lipsum                                    % This is typeset with letter-spacing
\end{document}

interletter_glue.stretch您可以通过更改(第三行)的值来控制允许的拉伸量letterspacing.lua(但请注意,通过设置,\emergencystretch我们明确告诉 TeX 在必要时超过该限制……但是,您通常不需要\emergencystretch使用字母间距,而在很多情况下您会需要它)。

相关内容