Letting Go of Type 1 Fonts

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

Version 1: cat(format(Sys.Date(), "%A %d %B %Y"))

opts_chunk$set(comment=" ", tidy=FALSE, dpi=96) options(width=100) ## For wonky desktop set up options(bitmapType="cairo") library(grid)

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).

The problem

The 'dvir' package (, , , ) 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$") ## Detach 'dvir' detach("package:dvir") unloadNamespace("dvir") ## Clean up metric PDF file that old 'dvir' leaves hanging around graphics.off()

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 () and we select LuaTeX as the TeX engine. This means that the TeX engine will use the Latin Modern Math font (), 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)

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) dvitxt <- capture.output(dvi) start <- grep("fnt_def", dvitxt)[1] stop <- rev(grep("set_char", dvitxt))[1] cat(dvitxt[start:stop], sep="\n")

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 kpsewhich -format=.pfb cmsy10

The problem with that is that Ubuntu 20.04 has a Pango () version above 1.44.

grSoftVersion()

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).

detach("package:dvir") unloadNamespace("dvir") graphics.off() 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)) detach("package:dvir") unloadNamespace("dvir") graphics.off() 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)) convert -density 96 workaround-embed.pdf workaround-embed.png

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") ## Detach 'dvir' detach("package:dvir") unloadNamespace("dvir") ## Clean up metric PDF file that old 'dvir' leaves hanging around graphics.off()

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 () automatically uses Latin Modern Roman () 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) ## Detach 'dvir' detach("package:dvir") unloadNamespace("dvir") ## Clean up metric PDF file that old 'dvir' leaves hanging around graphics.off()

The following code repeats the code from 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) ## Detach 'dvir' detach("package:dvir") unloadNamespace("dvir") ## Clean up metric PDF file that old 'dvir' leaves hanging around graphics.off()

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 () 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 (), 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 () 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 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) dvitxt <- capture.output(dvi) start <- grep("fnt_def", dvitxt)[1] stop <- rev(grep("set_char", dvitxt))[1] cat(dvitxt[start:stop], sep="\n") ## Detach 'dvir' detach("package:dvir") unloadNamespace("dvir") ## Clean up metric PDF file that old 'dvir' leaves hanging around graphics.off()

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.

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 section below).

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 ]

References


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