Fonts

General fonts overview

Font types

Fonts vary in structure and use, with each type having its own characteristics. Here’s an overview of the primary categories:

  1. Outline Fonts:

    • Examples: TrueType (TTF), OpenType (OTF), and Type 1 (often associated with PostScript).
    • Features: Characters are represented as outlines defined by mathematical curves and lines. This allows fonts to be scaled easily across a range of sizes without loss of quality.
  2. Bitmap Fonts:

    • Examples: PCF (Portable Compiled Format), FON (used in older versions of Windows).
    • Features: Characters are represented as a grid of pixels at a specific size and resolution. They are not scalable without loss of quality, meaning you’d need a different bitmap font file for each intended size.
  3. Stroke Fonts:

    • Examples: Hershey fonts.
    • Features: Characters are represented by a series of lines (or strokes). They can be thought of as a midpoint between bitmap and outline fonts. They define the “skeleton” of characters, allowing some scalability, but they don’t provide the same level of detail or flexibility as outline fonts.
Of the three, outline fonts are the most used in modern computing thanks to their scalability and versatility. This is the only font type we deal with in our normal practice.

Outline fonts

There are two essential components of an outline font:

  • Glyph outlines define the visual shape of each character in a font using mathematical curves, ensuring clarity at any size. Think of them as the “drawings” of each letter or symbol.

  • Metric data deals with a character’s positioning and relationship to other characters. It includes character widths, kerning (adjustments between specific character pairs), bounding boxes, and advancement (cursor movement after a character is drawn).

Together, these elements ensure text appears clear and well-spaced on screen or paper.

There are three primary outline font formats: TrueType (TTF), OpenType (OTF), and Type 1.

  • TrueType (TTF): This format stores font data in a single “.ttf” file, encompassing both glyph outlines and metric data. TrueType is both a standalone format and a foundation upon which OpenType was built.

  • Type 1: Often associated with PostScript fonts, this format traditionally splits its data. Glyph outlines reside in “.pfb” files, while metric data is contained in either “.pfm” or “.afm” files. The “.t1” extension, though less common, may be used in specific contexts for Type 1 font outlines.

  • OpenType (OTF): An evolution of TrueType, OpenType provides advanced typographic features. While “.otf” files are always OpenType fonts and typically incorporate PostScript (Type 1-style) outlines, the “.ttf” extension can indicate either a standard TrueType font or an OpenType font that utilizes TrueType outlines.

When you’re looking to add a new font family for use in R plots, a common approach is to download fonts from repositories such as Google Fonts. These downloads typically provide you with a “.ttf” file, or a collection of “.ttf” files, each representing different weights or styles within the font family. While these are labeled as TrueType files, they could be standard TrueType fonts or OpenType fonts that utilize TrueType features.

Fonts in Ubuntu

Standard Font Locations in Ubuntu

In Ubuntu and many Linux distributions, fonts can be stored in various standard locations depending on their intended accessibility and usage:

  • /usr/share/fonts: This directory is a system-wide font repository where applications typically look for fonts. Fonts stored here are available to all users on the system. It’s often populated with fonts that come pre-installed or are installed through software repositories.

  • /usr/local/share/fonts: This location is also system-wide but is more intended for fonts that are manually added by the administrator or through localized software installations. The distinction from /usr/share/fonts is that it’s meant to preserve locally added fonts, separate from those managed by the distribution’s package manager.

  • ~/.local/share/fonts: Aligning with the XDG Base Directory Specification, this directory is user-specific. Fonts placed here are only available to the user for whom the home directory (~) belongs. It’s the modern recommended location for individual users to add fonts without affecting the whole system.

  • ~/.fonts: An older, traditional location for user-specific fonts. While still functional in many systems, it’s gradually being superseded by ~/.local/share/fonts. Fonts in this directory are also exclusive to the individual user.

To ensure the broadest compatibility and adherence to system norms, it’s advised to place system-wide fonts in /usr/local/share/fonts and user-specific fonts in ~/.local/share/fonts.

While not obligatory, it’s a common practice to organize fonts within these directories using subfolders like “type1”, “opentype”, and “truetype”, which helps manage different font types more effectively. To verify the actual font file locations on your system using R, you can run View(systemfonts::system_fonts()) and inspect the path column.

Below is an illustrative structure of a typical fonts directory:

/usr/local/share/fonts/
└── truetype
    ├── AnekLatin
    │   ├── AnekLatin-Medium.ttf
    │   ├── AnekLatin-Regular.ttf
    │   └── AnekLatin-SemiBold.ttf
    ├── OpenSans
    │   ├── OpenSans-Italic.ttf
    │   ├── OpenSans-Light.ttf
    │   └── OpenSans-Regular.ttf
    └── Raleway
        ├── Raleway-Bold.ttf
        ├── Raleway-Light.ttf
        └── Raleway-Regular.ttf

Installing fonts on Ubuntu

When you acquire new fonts, they often come as .ttf or .otf files, either individually or within folders. To add them to your system place fonts in either /usr/local/share/fonts or ~/.local/share/fonts depending on whether you want them to be available for all users. Store .ttf files under the “truetype” subdirectory and .otf files in the “opentype” subdirectory.

Usually, this process is sufficient, even though some resources may suggest executing fc-cache -fv to rebuild the system’s font cache.

Fonts in R

Usually, installing fonts on your system is enough to access them in R. These fonts should display properly in the plotting window and in saved images. However, there are additional aspects to consider, which we’ll delve into next.

Registering fonts for pdf and PostScript with extrafonts

PDF (Portable Document Format) and PostScript are both page description languages used for representing documents in a manner that’s independent of the original software, hardware, or operating system. PostScript, an older format introduced in the 1980s, is now rarely used in practice.

While you might have fonts installed on your system, they won’t automatically work for PDF or PostScript graphics generated by R. These fonts need to be registered to ensure they’re rendered correctly. Registering a font means linking its name to its system file, allowing software to accurately display it. The font registration process in R is similar for both PostScript and PDF.

Although we barely ever produce R graphics in PDF format, and even less so in PostScript, there are reasons one may need to care about font registration. One of them is that the standard R CMD check uses the PostScript plotting device to generate plots within function examples. We’ll delve deeper into this topic in a subsequent chapter titled Maintaining a package with custom fonts.

With the extrafonts package, we facilitate the registration of fonts for both PDF and PostScript formats. There’s no need to obtain distinct font files for these formats. Instead, we adapt existing .ttf fonts for both PDF and PostScript compatibility. The entire procedure can be broken down into two main stages, importing fonts and registering fonts.

1. Importing Fonts

By directing the font_import() function to the location of your .ttf fonts, it will produce the necessary font files for both PDF and PostScript and store them in an internal registry. This storage utilizes the folder of the extrafontdb package, which acts more like a container for these files rather than a traditional package. If no specific paths are supplied to font_import(), it will use a set of default paths. You can check them by executing extrafont:::ttf_find_default_path(). Some of the standard paths may not be among them.

To view the font registry, run fonttable(). The afmfile column displays the names of font metric files (see the “Outline fonts” section above). These files are the generated by extrafont for use in pdf and postscript and housed within the extrafontdb folder. Meanwhile, glyphs are sourced directly from the .ttf files, and their respective locations can be found in the fontfile column.

The import step only needs to be executed once when you introduce new fonts.
The extrafont package relies on the Rttf2pt1 package to produce .afm font metric files. However, versions of Rttf2pt1 after 1.3.8 had issues generating these files on our main Ubuntu 20.04 system. For our g6tr.theme package, which offers plot theming functions reliant on specific fonts, we specified the Rttf2pt1 version to be 1.3.8. Though this issue has been addressed, we retain this note as a precaution for potential future occurrences.

2. Registering Fonts

Use the loadfonts() function to register fonts from the extrafontdb database for both PDF and PostScript. While we suggest keeping the device parameter unmodified, you can adjust it if needed. Setting it to “postscript” will register only postscript fonts. However, choosing “pdf” will register both postscript and pdf fonts. On Ubuntu, this “pdf” choice is equivalent to the default “all” option.

After registration, you can verify the loaded fonts with the pdfFonts() and postscriptFonts() functions.

Font registrations are session-bound, requiring renewal each session.

Font embedding

When saving plots in PDF format with the intention of sharing them with others, it’s essential to consider font embedding. Font embedding is the process of including the font information within the PDF file itself. This ensures that the recipient of the PDF will see the text exactly as intended, even if they don’t have the same fonts installed on their system. To embed fonts into a PDF generated using R, you can utilize the embed_fonts() function provided by the extrafont package. For more detailed instructions and information, you can refer to the package readme.

Font matching

In R graphics, you set fonts by specifying both the font family and font face, with common faces being plain, italic, bold, or bold italic. Although the family name is embedded within the font file and not dictated by the file name, you can often infer the family from the file name. However, there are exceptions, making the process occasionally tricky.

The output from systemfonts::system_fonts() can sometimes be counterintuitive in this regard. For instance, a ‘Medium’ variation of font X might be displayed with ‘X’ in the family column and ‘Medium’ in the style column. However, to apply this variation in a plot, you’d set the family to ‘X Medium’. In contrast, for a ‘Bold’ variation, even though it’s listed with family = ‘X’ and style = ‘Bold’, you’d use the family ‘X’ and set the fontface to ‘bold’ in your plot.

To view the list of font families recognized by your system, it’s advisable to use system commands such as fc-list : family instead.

To see how R graphics match fonts by family and fontface, you can use the systemfonts::match_font() function. Interestingly, this function reveals that the family parameter is case insensitive and can tolerate random spaces between letters.

However, this flexibility doesn’t extend to PDF and PostScript fonts. Only the family values displayed in the outputs of pdfFonts() and postscriptFonts() are valid. It’s advisable to use these values as they are, without alterations, to ensure compatibility.

One thing to understand about font matching is the concept of the default font. If you provide an unrecognized value to the family parameter of systemfonts::match_font(), it will return a designated fallback font. Essentially, when the family parameter is set to an unknown value, the system quietly resorts to using the default font, without raising any errors. However, for PDF and PostScript graphics, the behavior is different. If the family is not recognized, R will throw an error.

Maintaining a package with custom fonts

If you’re developing an R package that incorporates custom fonts, it’s essential to ensure that users can easily access these fonts upon the package’s installation. One strategy is to include the font files within the package’s “inst” directory. Additionally, you should add code to the package’s .onLoad() function to install these fonts if they aren’t already present on the system.

For users on Ubuntu, the installation means moving font files from the package installation directory (system.file(package = "g6tr.theme")) to the user-specific font directory at ~/.local/share/fonts. It’s not advisable to place fonts in the system-wide font directory because users may lack the permissions to access or modify it.

For Windows users, font registration is similar to how fonts are registered for PDF and PostScript formats.

An essential consideration during the standard R CMD check is that it runs all code examples (excluding those marked with dontrun) to verify their correct operation. If examples produce plots, they use the default system graphic device. On many non-Windows systems, including Ubuntu, this device defaults to PostScript. Hence, ensuring that fonts are correctly registered for PostScript is vital.

Practically, as detailed in the Registering fonts for PDF and PostScript with extrafonts section:

  1. Import fonts into the extrafontdb database, but only if they haven’t been added before.
  2. Register them using extrafont::loadfonts(). On Windows, this will also automatically register Windows fonts.

Here’s what the .onLoad function might look like in pseudocode to ensure custom fonts are ready:

.onload <- function(...) {
   package_fonts_dir <- system.file("fonts", package = "package_name")
   user_fonts_dir <- "~/.local/share/fonts/truetype"
   
   if (system is linux) {
      if (any of the package fonts is not in user_fonts_dir) {
        copy the font files to user_fonts_dir
      }
   }
   
   fonts_in_extrafontdb <- extrafont::fonttable()
   if (any of the package fonts is not in fonts_in_extrafontdb) {
     extrafont::font_import(package_fonts_dir, prompt = FALSE)
   }
   
   # register fonts for pdf and postscript device
   # if on Windows, also registers windows fonts
   extrafont::loadfonts(device = "all", quiet = TRUE)
}