# sidenote

In one of my latest posts I mentioned a question about how to draw individual glyphs with randomized paths on TeX.SX. Today I want to share the answer I posted about two weeks ago, and some related stuff which I’ve made during and after working on the answer.

Let’s see the question first. It is quoting Donald Knuth’s article, Mathematical typography from the Bulletin of the American Mathematical Society. Randomization. I’d like to report on a little experiment I did with random numbers. One might complain that the letters I have designed are too perfect, too much like a computer, so they lack “character”. In order to counteract this, we can build a certain amount of randomness into the choices of where to put the pen when drawing each letter, and Figure 21 shows what happens. The coordinates of the key pen positions where chosen independently with a normal distribution and with increasing standard deviation, so that the third example has twice as much standard deviation as the second, the fourth has three times as much, and so on. Note that the two m’s on each line (except the first) are different, and so are the a’s and the t’s, since each letter is drawn randomly.

The question was how to achieve a similar effect in LaTeX without using MetaFont. You can read the answer below, but if you feel tl;dr skip below the long quote for my related works.

I have been thinking about this question for weeks now, and finally I think I came really close to a result you may also like. I have even tried to use Processing to solve this problem, which resulted in a nice animation as a byproduct, but it didn’t lead me closer to the solution. But back to the point…

Unfortunately the solution I’m posting, which is my best and only shot, does not support drawing the distorted glyphs as text but as drawings. Also there is some work to be done outside the context of LaTeX, but most of it is done in LaTeX (LuaTeX + TikZ). The picture above shows an undistorted glyph (character “a” on the left in the line at the top), a distorted glyph (character “a” on the right in the line at the top), a word consisting of distorted glyphs (middle line), and a special character (Omega), all these can be found in the code at the end of the answer.

Now I will describe the process I have followed to achieve these distortions. I mentioned that there is some work to be done outside of LaTeX, that is to convert a font file into SVG using FontForge. I found the solution how to do this in an answer to the question: Can we extract the points making the character from the font file?

Copy the following into a file named font2svg.pe into your “project” folder.

 123 #!/usr/bin/env fontforge Open($1) Generate($1:t:r + ".svg")

And make a SVG file from the font you want to use (I chose cmr10) with the following command.

fontforge font2svg.pe /usr/local/texlive/2014/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb

Note that the location of the font on the filesystem may vary based on your LaTeX installation and operating system you use, but this will generate an SVG file into your project folder. All is left to process the generated SVG file which contains the data (name, unicode code, width, and outline) of the glyphs, which I will describe below.

The function function read_font_data(file) takes a file name as an argument (the generated SVG file), and extracts the data of the glyphs into an associative array which can be addressed with the unicode code and contains the width and outline data of the specific character. Note that not all glyphs have width or outline data, some basic error checking is done but the code is not foolproof.

The function random_in_interval(lower_boundary, upper_boundary) takes two float arguments, and will return a random float between them. The more the boundaries converge to 1 the smaller the randomization will be. This will be used when the time comes to randomize the outline of a glyph.

The function scale_and_randomize(glyph, scale_factor, lower_boundary, upper_boundary) will take a glyph, a scale factor, a lower and upper boundary, the latter two will be used for the randomization. Scaling is needed because the default measurement unit of TikZ is centimeters (I think) and the outline data of a glyph may contain large values, which TikZ interprets as centimeters. Note that the scale factor may vary depending the font you use, and size you want.

The functions print_glyph(glyph, scale_factor, lower_boundary, upper_boundary) and return_glyph (the latter takes the same arguments) only differ in that print_glyph will pass the TikZ drawing command (using svg.path library) used to print the glyph to LaTeX, while return_glyph only returns the drawing command as a string which can be further used in Lua before passing it to LaTeX.

The remaining functions only use the previously described print_glyph and return_glyph functions to print the picture above.

That’s it. I hope this would fit your needs.

 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 % Randomized drawing of individual glyphs % Author: IstvÃĄn SzÃĄntai (szantaii) % Original at: http://tex.stackexchange.com/a/197677/8844 \documentclass[10pt, a4paper]{article} \usepackage[T1]{fontenc} \usepackage{luacode} \usepackage{tikz} \usetikzlibrary{svg.path, positioning} \pagestyle{empty} \tikzset{%     glyph node/.style={%         inner sep=0pt,%         outer sep=0pt%     },%     glyph outline/.style={%         line width=0pt%     }% } \begin{luacode*}     function read_font_data(file)         local glyphs = {}         local fd = io.open(file, "r")         local content = fd:read("*all")         fd.close()                 for glyph in string.gmatch(content, "]*") do             local glyph_tag = string.gsub(glyph, "\n", " ")             local unicode = string.match(glyph_tag, "unicode="[^"]*")             local outline = string.match(glyph_tag, "d="[^"]*")             local width = string.match(glyph_tag, "horiz%-adv%-x="[^"]*")                         if unicode ~= nil and #unicode >= 10 then                 unicode = string.sub(unicode, 10, #unicode)             end                         if outline ~= nil and #outline > 4 then                 outline = string.sub(outline, 4, #outline)             end                         if width ~= nil and #width >= 14 then                 width = string.sub(width, 14, #width)             end                         if unicode ~= nil then                 glyphs[unicode] = {width, outline}             end         end                 return glyphs     end         -- returns a random float number between the specified boundaries (floats)     function random_in_interval(lower_boundary, upper_boundary)         return ((math.random() * (upper_boundary - lower_boundary)) + lower_boundary)     end         -- note: scaling is applied before randomization     function scale_and_randomize(glyph, scale_factor, lower_boundary, upper_boundary)         local width = glyph         local outline = glyph                 local previous_was_number = false         local processed_outline = ""         local number = ""                 if width ~= nil then             width = width * scale_factor         end                 if outline ~= nil then             for i = 1, #outline, 1 do                 local char = string.sub(outline, i, i)                                 if previous_was_number then                     if string.match(char, '%d') ~= nil or                         char == "." then                         number = number .. char                     else                         -- scale and randomize                         number = number * scale_factor                         number = number * random_in_interval(lower_boundary, upper_boundary)                         number = string.format("%.3f", number)                         processed_outline = processed_outline .. number .. char                         number = ""                         previous_was_number = false                     end                 else                     if string.match(char, '%d') ~= nil or                         char == "-" then                                                 number = number .. char                         previous_was_number = true                     else                         processed_outline = processed_outline .. char                         previous_was_number = false                     end                 end             end         end                 return {width, processed_outline}     end         function print_glyph(glyph, scale_factor, lower_boundary, upper_boundary)         local randomized_glyph = scale_and_randomize(glyph, scale_factor, lower_boundary, upper_boundary)         local width = randomized_glyph         local outline = randomized_glyph         if outline ~= nil then             tex.sprint("\\filldraw[glyph outline] svg "" .. outline .. "";")         end     end         function return_glyph(glyph, scale_factor, lower_boundary, upper_boundary)         local randomized_glyph = scale_and_randomize(glyph, scale_factor, lower_boundary, upper_boundary)         local width = randomized_glyph         local outline = randomized_glyph                 if outline ~= nil then             return "\\filldraw[glyph outline] svg "" .. outline .. "";"         else             return ""         end     end         function draw_sample_glyphs(glyphs)         tex.sprint("\\begin{tikzpicture}")         tex.sprint("\\node[glyph node, matrix, anchor=south west] (a1) {" ..             return_glyph(glyphs["a"], 0.05, 1, 1) ..             "\\\\};")         tex.sprint("\\node[glyph node, matrix, anchor=south west, right=7.5mm of a1] (a2) {" ..             return_glyph(glyphs["a"], 0.05, 0.8, 1.2) ..             "\\\\};")         tex.sprint("\\end{tikzpicture}")     end         function draw_sample_text(glyphs)         local horizontal_space = "0.5mm"         local vertical_space = "1.25mm"         local scale = 0.05         local lower_boundary = 0.9         local upper_boundary = 1.1                 tex.sprint("\\begin{tikzpicture}")         tex.sprint("\\node[glyph node, matrix] (m1) {" ..             return_glyph(glyphs["m"], scale, lower_boundary, upper_boundary) ..             "\\\\};")                 tex.sprint("\\node[glyph node, matrix, right=" .. horizontal_space ..             " of m1] (a1) {" ..             return_glyph(glyphs["a"], scale, lower_boundary, upper_boundary) ..             "\\\\};")                 tex.sprint("\\node[glyph node, matrix, right=" .. horizontal_space ..             " of a1] (t1) {" .. "\\raisebox{" .. vertical_space .. "}{" ..             return_glyph(glyphs["t"], scale, lower_boundary, upper_boundary) ..             "}" .. "\\\\};")                 tex.sprint("\\node[glyph node, matrix, right=" .. horizontal_space ..             " of t1] (h1) {" .. "\\raisebox{" .. vertical_space .. "}{" ..             return_glyph(glyphs["h"], scale, lower_boundary, upper_boundary) ..             "}" .. "\\\\};")                 tex.sprint("\\node[glyph node, matrix, right=" .. horizontal_space ..             " of h1] (e1) {" ..             return_glyph(glyphs["e"], scale, lower_boundary, upper_boundary) ..             "\\\\};")                 tex.sprint("\\node[glyph node, matrix, right=" .. horizontal_space ..             " of e1] (m2) {" ..             return_glyph(glyphs["m"], scale, lower_boundary, upper_boundary) ..             "\\\\};")                 tex.sprint("\\node[glyph node, matrix, right=" .. horizontal_space ..             " of m2] (a2) {" ..             return_glyph(glyphs["a"], scale, lower_boundary, upper_boundary) ..             "\\\\};")                 tex.sprint("\\node[glyph node, matrix, right=" .. horizontal_space ..             " of a2] (t2) {" .. "\\raisebox{" .. vertical_space .. "}{" ..             return_glyph(glyphs["t"], scale, lower_boundary, upper_boundary) ..             "}" .. "\\\\};")                 tex.sprint("\\node[glyph node, matrix, right=" .. horizontal_space ..             " of t2] (i1) {" .. "\\raisebox{" .. vertical_space .. "}{" ..             return_glyph(glyphs["i"], scale, lower_boundary, upper_boundary) ..             "}" .. "\\\\};")                 tex.sprint("\\node[glyph node, matrix, right=" .. horizontal_space ..             " of i1] (c1) {" ..             return_glyph(glyphs["c"], scale, lower_boundary, upper_boundary) ..             "\\\\};")                 tex.sprint("\\node[glyph node, matrix, right=" .. horizontal_space ..             " of c1] (s1) {" ..             return_glyph(glyphs["s"], scale, lower_boundary, upper_boundary) ..             "\\\\};")         tex.sprint("\\end{tikzpicture}")     end         function draw_sample_glyph(glyphs)         tex.sprint("\\begin{tikzpicture}")         print_glyph(glyphs["Ω"], 0.05, 0.95, 1.05)         tex.sprint("\\end{tikzpicture}")     end         function main()         local cmr10_glyphs = {}                 math.randomseed(os.time())                 cmr10_glyphs = read_font_data("cmr10.svg")                 tex.sprint("\\noindent")         draw_sample_glyphs(cmr10_glyphs)         tex.sprint("\\\\[2cm]")         draw_sample_text(cmr10_glyphs)         tex.sprint("\\\\[2cm]")         draw_sample_glyph(cmr10_glyphs)     end \end{luacode*} \begin{document} \luadirect{main()} \end{document}

Nice, isn’t it?

I’ve created an animation in LaTeX (clarification later) using this code, which makes the letter “a” wibbly-wobbly. There is also a video which shows the same letter but only the outline is drawn, but in my opinion it doesn’t look that good: Glyph distortion – YouTube.

These videos are also available on Vimeo: Glyph distortion on Vimeo, Glyph distortion #2 on Vimeo.

The second animation (also made in LaTeX) draws a big letter “a” stacking only outlines of it on top of each other which it gives a hollow like look.

This video is also available on Vimeo: Font outline animation #2 on Vimeo.

Only one question remains, how did I made these animations in LaTeX? I just built upon the code above, and rendered a long PDF which’s each page is a frame of the animation. After that I only followed some steps I’ve described before.

MegosztÃĄs, like stb.