Fonts
Fonts vary in structure and use, with each type having its own characteristics. Here’s an overview of the primary categories:
-
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.
-
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.
-
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.
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.
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/fontsis 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
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.
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.
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.
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.
Theextrafontpackage relies on theRttf2pt1package to produce .afm font metric files. However, versions ofRttf2pt1after 1.3.8 had issues generating these files on our main Ubuntu 20.04 system. For ourg6tr.themepackage, which offers plot theming functions reliant on specific fonts, we specified theRttf2pt1version to be 1.3.8. Though this issue has been addressed, we retain this note as a precaution for potential future occurrences.
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.
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.
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.
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:
- Import fonts into the
extrafontdbdatabase, but only if they haven’t been added before. - 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)
}