Letting Go of Type 1 Fonts

by Paul Murrell http://orcid.org/0000-0002-3224-8858

Version 1: Tuesday 22 December 2020


Creative Commons License
This document by Paul Murrell is licensed under a Creative Commons Attribution 4.0 International License.


The 'dvir' package for R is limited in that it is only known to work on an (Ubuntu) Linux distribution with (at least) a full TeX installation. Unfortunately, not even that is true for recent stable Linux releases, like Ubuntu 20.04, because of a dependence on Type 1 fonts. This report describes an update to the 'dvir' package, plus some guidelines on avoiding Type 1 fonts, so that 'dvir' will work on recent stable Linux distributions (or at least Ubuntu 20.04).

Table of Contents:

1. The problem

The 'dvir' package (Murrell, 2020c, Murrell, 2018, Murrell, 2020b, Murrell, 2020a) provides functions for rendering TeX output on R graphics devices. For example, the following code renders a simple TeX mathematical expression in R graphics (on Ubuntu 18.04).

library(dvir)
grid.latex("$x - \\mu$")

Unfortunately, not even that simple example works on recent stable Linux distributions. For example, the output below shows what 'dvir' (version 0.3-0) produces on Ubuntu 20.04.

library(dvir, lib.loc="/opt/R/dvir/version-0.3-0")
grid.latex("$x - \\mu$")
plot of chunk unnamed-chunk-4

2. The solution

There are two steps involved in the solution to this problem:

  1. Ensure that the TeX engine makes use of an Open Type (or True Type) font, rather than a Type 1 font.
  2. Use the latest version of 'dvir', version 0.3-1 or higher.

The following code provides a simple demonstration. First, we load version 0.3-1 of the 'dvir' package. Then, we need to complicate the call to grid.latex a little bit. The core TeX code is still just a simple equation, but we specify a preamble that loads the unicode-math package (Robertson et al., 2019) and we select LuaTeX as the TeX engine. This means that the TeX engine will use the Latin Modern Math font (Jackowski et al., 2014), which is an Open Type font, and the resulting output is back to what we would like.

library(dvir, lib.loc="/opt/R/dvir/version-0.3-1")
preamble <- "
\\documentclass[12pt]{standalone}
\\usepackage{unicode-math}
\\begin{document}
"
grid.latex("$x - \\mu$",
           preamble=preamble,
           engine=lualatexEngine)
plot of chunk unnamed-chunk-6

3. The details

This section explains the problem, and the solution, in more detail.

LaTeX uses Type 1 fonts by default

The following output shows the relevant part of the DVI output that is generated by the default LaTeX engine on Ubuntu 20.04.

dviFile <- typeset("$x - \\mu$")
dvi <- readDVI(dviFile)
  fnt_def_1    fontnum=27, checksum=-1209964637, scale=786432, design=786432,
               fontname=cmmi12
  fnt_num_27
  set_char_120 'x'
  w3           b=174760 
  fnt_def_1    fontnum=30, checksum=555887770, scale=786432, design=655360,
               fontname=cmsy10
  fnt_num_30
  set_char_0   ''
  w0 
  fnt_num_27
  set_char_22  ''

The fnt_def_1 operations show that LaTeX has used cmmi12 (Computer Modern Math Italic) and cmsy10 (Computer Modern Symbol) fonts to typeset the equation. These are Type 1 (.pfb) fonts.

kpsewhich -format=.pfb cmmi12
  /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi12.pfb
kpsewhich -format=.pfb cmsy10
  /usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy10.pfb

The problem with that is that Ubuntu 20.04 has a Pango (Taylor et al., 2020) version above 1.44.

grSoftVersion()
                     cairo                  cairoFT                    pango                   libpng 
                  "1.16.0"                       ""                 "1.44.7"                 "1.6.37" 
                      jpeg                  libtiff 
                     "8.0" "LIBTIFF, Version 4.1.0"

The problem with that is that Pango versions above 1.44 have abandoned support for Type 1 fonts and the problem with that is that R's Cairo-based graphics devices make use of Pango for typesetting text, so when grid.latex attempts to draw text using the same Type 1 fonts that the TeX engine used, on the default (Linux) graphics device (a Cairo X11 window or a Cairo PNG file), it fails. The result is the boxes containing hexadecimal values that indicate missing glyphs.

A PDF/PostScript workaround

The problem is limited to Cairo-based graphics devices, so a relatively simple workaround is to draw on a PDF or PostScript graphics device instead. The following code demonstrates that this workaround works on Ubuntu 20.04 even with the old version of 'dvir' (0.3-0).

library(dvir, lib.loc="/opt/R/dvir/version-0.3-0")
dg <- dviGrob(dvi)
pdf("workaround.pdf", width=2, height=1)
grid.draw(dg)
dev.off()
embedFonts("workaround.pdf", outfile="workaround-embed.pdf",
           fontpaths=fontPaths(dg))

Getting latex to avoid Type 1 fonts

If we want to use the Cairo-based graphics devices on a recent stable Linux, we must avoid Type 1 fonts. This means that we must make sure that the TeX engine does not use Type 1 fonts because 'dvir', by design, uses exactly the same fonts that the TeX engine uses.

To demonstrate the problem again, the following code shows that, even with simple text, the default LaTeX engine produces an undesirable result (on Ubuntu 20.04, on a Cairo-based device, because it uses Type 1 fonts).

library(dvir, lib.loc="/opt/R/dvir/version-0.3-0")
grid.latex("Test")
plot of chunk unnamed-chunk-16

One easy way to avoid Type 1 fonts is to use the LuaTeX engine, rather than the default LaTeX engine, because LuaTeX makes it easy to select different fonts. Then it is just a matter of selecting an Open Type or True Type font in the TeX code.

For a standard Computer Modern look, the lmodern package (Harders, 2020) automatically uses Latin Modern Roman (Jackowski et al., 2020) as the default (Open Type) font.

The following code shows that using the LuaTeX engine (and version 0.3-1 of 'dvir') and loading the lmodern package fixes the problem (because we are now using an Open Type font; Latin Modern Roman).

library(dvir, lib.loc="/opt/R/dvir/version-0.3-1")
preamble <- "
\\documentclass[12pt]{standalone}
\\usepackage{lmodern}
\\begin{document}
"
grid.latex("Test",
           preamble=preamble,
           engine=lualatexEngine)
plot of chunk unnamed-chunk-19

The following code repeats the code from The solution Section. This shows that using the LuaTeX engine and loading the unicode-math package, which automatically loads the Latin Modern Math (Open Type) font for TeX math mode, fixes the problem for a simple equation.

library(dvir, lib.loc="/opt/R/dvir/version-0.3-1")
preamble <- "
\\documentclass[12pt]{standalone}
\\usepackage{unicode-math}
\\begin{document}
"
grid.latex("$x - \\mu$",
           preamble=preamble,
           engine=lualatexEngine)
plot of chunk unnamed-chunk-22

Improvements to the 'dvir' package

In addition to making sure that the TeX engine uses an Open Type or True Type font, we also need to use the updated version of 'dvir' (0.3-1).

This new version contains two important changes. First of all, 'dvir' now makes use of the 'systemfonts' package (Pedersen et al., 2020) to get information about installed fonts. This is because the systemfonts::system_fonts function can tell us about Open Type fonts. Previous versions of 'dvir' made use of the fonttable function from the 'extrafont' package (Chang, 2014), but that can only tell us about True Type fonts.

One complication is the fact that system_fonts does not include information about .afm files (while fonttable does), for the very good reason that Open Type fonts do not have .afm files. Only Type 1 fonts have .afm files, which contain metric information about the glyphs in the font. R graphics makes use of .afm files when drawing to a PDF or PostScript device. The 'extrafont' package actually generates .afm files for True Type fonts (so that they can be used on PDF and PostScript devices). However, we are interested here in using Open Type fonts on Cairo-based devices, so the lack of .afm information is not a problem. The 'dvir' package uses TTX (van Rossum et al., 2020) to extract metric information from the Open Type font. Using Open Type fonts on PDF and PostScript devices is still an issue, but we will leave that for another day.

The second important change in 'dvir' version 0.3-1 involves the support of set_char3 operations in DVI files. These operations specify a character to draw as a 3-byte value. Previously, 'dvir' has assumed that these operations only represent non-UNICODE glyphs in a font (where the first byte is 0F; see Murrell, 2020b for details). This assumption is horribly exposed by the simple math equation example (when we use an Open Type font). The following output shows the relevant DVI code generated by the LuaTeX engine using the unicode-math package.

library(dvir, lib.loc="/opt/R/dvir/version-0.3-1")
preamble <- "
\\documentclass[12pt]{standalone}
\\usepackage{unicode-math}
\\begin{document}
"
dviFile <- typeset("$x - \\mu$",
                   preamble=preamble,
                   engine=lualatexEngine)
dvi <- readDVI(dviFile)
  fnt_def_1    fontnum=29, checksum=0, scale=786432, design=655360,
               fontname=[latinmodern-math.otf]:mode=base;script=math;language=dflt;
  fnt_num_29
  set_char3    01 d4 65
  right3       b=174744
  set_char2    22 12
  right3       b=174744
  set_char3    01 d7 07

This shows that both the 'x' and the mu characters are represented by set_char3 operations (01 d4 65 and 01 d7 07). These specify the character to draw as UNICODE code points in UTF-32 encoding (with the first byte assumed to be zero). Version 0.3-1 of 'dvir' now handles set_char3 operations of this type.

Summary

When using 'dvir' on a recent stable Linux, like Ubuntu 20.04, use the LuaTeX engine, write TeX code that selects an Open Type or True Type font, and use 'dvir' version 0.3-1 or higher.

4. Technical requirements

The examples and discussion in this document relate to version 0.3-1 of the 'dvir' package.

This report was generated within a Docker container (see the Resources section below).

5. Resources

How to cite this document

Murrell, P. (2020). "Letting Go of Type 1 Fonts" Technical Report 2020-06, Department of Statistics, The University of Auckland. version 1. [ bib | DOI | http ]

6. References

[Chang, 2014]
Chang, W. (2014). extrafont: Tools for using fonts. R package version 0.17. [ bib | http ]
[Harders, 2020]
Harders, H. (2020). The lmodern package for TeX. [ bib | http ]
[Jackowski et al., 2020]
Jackowski, B., Nowacki, J. M., and Wolinski, M. (2020). The Latin Modern (LM) Family of Fonts. [ bib | http ]
[Jackowski et al., 2014]
Jackowski, B., Strzelczyk, P., and Pianowski, P. (2014). The Latin Modern Math (LM Math) font. [ bib | http ]
[Murrell, 2018]
Murrell, P. (2018). Revisiting mathematical equations in R: the 'dvir' package. Technical Report 2018-08, Department of Statistics, The University of Auckland. version 2. [ bib ]
[Murrell, 2020a]
Murrell, P. (2020a). Adding tikz support to 'dvir'. Technical Report 2020-05, Department of Statistics, The University of Auckland. version 1. [ bib | DOI | http ]
[Murrell, 2020b]
Murrell, P. (2020b). The agony and the ecstacy: Adding luatex support to 'dvir'. Technical Report 2020-02, Department of Statistics, The University of Auckland. version 1. [ bib | DOI | http ]
[Murrell, 2020c]
Murrell, P. (2020c). dvir: Render DVI Files. R package version 0.3-1. [ bib ]
[Pedersen et al., 2020]
Pedersen, T. L., Ooms, J., and Govett, D. (2020). systemfonts: System Native Font Finding. R package version 0.3.2.9000. [ bib | http ]
[R Core Team, 2020]
R Core Team (2020). R: A Language and Environment for Statistical Computing. R Foundation for Statistical Computing, Vienna, Austria. [ bib | http ]
[Robertson et al., 2019]
Robertson, W., Stephani, P., Wright, J., and Hosny, K. (2019). unicode-math: Unicode mathematics support for XeTeX and LuaTeX. [ bib | http ]
[Taylor et al., 2020]
Taylor, O., Levien, R., and Esfahbod, B. (2020). Pango. [ bib | http ]
[van Rossum et al., 2020]
van Rossum, J., Wise, P., and Esfahbod, B. (2020). FontTools: A library to manipulate font files from Python. [ bib | http ]

Creative Commons License
This document by Paul Murrell is licensed under a Creative Commons Attribution 4.0 International License.