8

In the book The Complete Manual of Typography by James Felici, it is recommended to sometimes alter the spaces between letters in order not to stretch the inter-word spaces too dramatically.

enter image description here

I have tried using Tracking from microtype package, but I can only set it to the constant value. There is also LetterSpace option in fontspec, but it seems to do pretty the same.

Can this be done in LuaLaTeX?

\documentclass{article}

\usepackage{lipsum}

\usepackage{fontspec}

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

\SetTracking{
    family  =   *}{10} 

\begin{document}

    \lipsum

\end{document}
  • A related link from the typography perspective: it's worth knowing that typographers' opinions on such letter spacing (and font expansion: basically all the features provided by microtype!) differ. – ShreevatsaR Nov 14 '17 at 15:31
  • @ShreevatsaR AFAIK there is a big controversy around the expansion, but i find alterning the spaces OK. Is this very feature provided by microtype? – Michael Fraiman Nov 14 '17 at 15:41
8

Although typographers differ in their opinion on letter spacing, when setting justified text in narrow columns we have to settle for some compromise somewhere (which includes considering ragged-right text), and letter spacing seems acceptable. So I am shocked that the microtype package does not seem to provide this feature; after all it is extensively discussed in Hàn Thế Thành's thesis Micro-typographic extensions to the TeX typesetting system. I am still not sure whether I simply missed something in the microtype documentation, though I looked through it several times for this feature.

Anyway, this is easy to do with LuaTeX. There are multiple approaches: for example, after line-breaking (in post_linebreak_filter) we could add the appropriate amount of stretch between nodes (this is the approach discussed in Hàn Thế Thành's thesis, section 6.8). Or else, before line-breaking (in pre_linebreak_filter) we could add stretchable glue nodes. The second approach is implemented in the chickenize package, as \letterspaceadjust. It's just a handful of lines of code, so we can copy it and make changes if we desire (in the code sample below I change only letterspace_glue.stretch from 0.5 pt to 10pt).

output

\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}

Just for clarity, here is the relevant code again, without loading it from a package. Put the following in a file called 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.")

Now you can typeset the following file with 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}

You can control the amount of allowed stretching by changing the value of interletter_glue.stretch (third line of letterspacing.lua) (though note that by setting \emergencystretch we're explicitly telling TeX to exceed that limit if necessary… however, you usually won't need \emergencystretch with letter-spacing, in many cases where you would have needed it otherwise).

  • I also haven't seen this feature in microtype, which is strange. Where exactly is the tracking controlled in your code? – Michael Fraiman Nov 14 '17 at 20:00
  • @MichaelFraiman Search for letterspace_glue.stretch in the code… I added another version to try to make this clearer (in which search for interletter_glue.stretch). – ShreevatsaR Nov 14 '17 at 20:56
  • microtype doesn't provide this feature because pdftex doesn't: paragraph composition with variable letterspacing was possible in early versions, but this was later dropped, leaving font expansion as the only option to improve justification. – Robert Nov 15 '17 at 4:20
  • @Robert Thank you so much! That explains it… makes sense now. – ShreevatsaR Nov 15 '17 at 4:32
  • Just to note that the output would be improved if the glue were also allowed to shrink. – Robert Nov 17 '17 at 3:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.