Configuring Custom Fonts

Information

PSPDFKit Server has been deprecated and replaced by PSPDFKit Document Engine. All PSPDFKit Server and PSPDFKit for Web Server-Backed licenses will work as before and be supported until 15 May 2024 (we will contact you about license migration). To start using Document Engine, refer to the migration guide. With Document Engine, you’ll have access to robust new capabilities (read the blog for more information).

PDF files are supposed to be rendered exactly the same, no matter which PDF viewer you’re using. One reason why this is the case is because a PDF file can embed the fonts required to render it.

However, sometimes — due to the size or other considerations — fonts aren’t embedded, which makes the PDF viewer look for fonts on the current system. Depending on the fonts that are available, this can cause rendering problems.

While the best option is to always embed fonts in the PDF, this isn’t always possible, especially if you’re working with third-party PDF files. This is where custom font path support comes in.

A font that includes all characters is usually more than 200 MB in size, which is difficult for a web browser to render. So, to render fonts effectively (and to ensure this works in older browsers), a server is necessary. That’s why we built custom font path support into PSPDFKit Server.

You can expose a directory of fonts from the host machine to the Docker container by adding the following to your docker-compose.yml file:

pspdfkit:
  volumes:
    - /font-directory-path-on-the-host:/custom-fonts

Note that after you add the fonts, you might still see PDFs rendered with an incorrect font in the web viewer. This is because there are multiple layers of caching involved, and you’re still seeing the old rendered page. To solve this, follow these steps:

  1. Clear the browser cache — This clears rendering artifacts cached by the browser.

  2. Restart PSPDFKit Server — This clears the in-memory server cache for rendered pages.

  3. Only if you use Redis — Delete the keys, starting with the PSPDFKit-TileCache- and PSPDFKit-PageCache- prefixes, to remove all rendered artifacts cached by PSPDFKit Server. Note that there may be considerable performance implications in the case of high-volume deployments (since all the previously cached pages will need to be rerendered by PSPDFKit Server), in which case, you’ll need to apply Redis eviction policies that will remove the keys from the cache gradually.

The font directory can be any directory that’s accessible to your app, and all .ttf, .ttc, and .otf files will be added to the font list of PSPDFKit.

Microsoft Core Fonts

Microsoft core fonts are widely used on the web and in PDF files. Including them as custom fonts in your project improves the conversion and rendering fidelity for documents that use them. These fonts aren’t included in PSPDFKit because Microsoft no longer offers these files directly, and the license prohibits redistribution. To use these fonts in your project, download them from SourceForge and add them to PSPDFKit as a custom font.

Using Emojis

To use emojis in your project, import the Windows-compatible Noto Color Emoji font. Currently, this is the only supported font for displaying emojis.

Font Substitutions

Sometimes, PSPDFKit Server doesn’t have access to the font required to perform a conversion or render an annotation either as part of the default container fonts or in the fonts directory mounted at /custom-fonts, as described above.

In these cases, it’s necessary to specify alternative fonts that can be used in place of the unavailable fonts. To specify these substitute fonts, create a font-substitutions.json file and mount it on the PSPDFKit Server container:

pspdfkit:
  volumes:
    - /path-to-font-substitutions-json-on-host:/font-substitutions.json

The schema for the font-substitutions.json file is as follows (TypeScript is used for this definition):

type FontSubstitutions = {
  fontSubstitutions: FontSubstitution[];
};

type FontSubstitution = {
  // Please note that font family name replacements are made based upon pattern matching,
  // allowing for a font family name to be replaced with a different name.
  // Patterns are matched using the following rules:
  //  - `*` matches multiple characters
  //  - `?` matches a single character
  pattern: string;

  // The font that should be used as a replacement
  // when any font matching the given pattern is unavailable.
  target: string;
};

Example font-substitions.json file:

{
  "fontSubstitutions": [
    {
      "pattern": "Roboto-*",
      "target": "Courier New"
    },
    {
      "pattern": "Calibri",
      "target": "Caladea"
    }
  ]
}

Notes on Font Substitutions

Case-Insensitive — The pattern and target names are case-insensitive.

Ordering Matters — As names could match multiple patterns, it’s important to note that the order of substitutions in the fontSubstitutions array matters. Specifically, the font substitutions are processed from top down.

For example, consider the following list of font substitutions:

{
  "fontSubstitutions": [
    {
      "pattern": "Roboto-*",
      "target": "Courier New"
    },
    {
      "pattern": "Roboto-Medium",
      "target": "Menlo"
    },
    {
      "pattern": "Roboto-Medium*",
      "target": "Consolas"
    }
  ]
}

If PSPDFKit Server has to convert a document with Roboto-MediumItalic font and the Roboto-MediumItalic font is unavailable, it’ll use the Courier New font as a substitute instead (provided Courier New is available), since Roboto-* is the first match for Roboto-MediumItalic on the list.

The font substitutions specified using font-substitutions.json will be applied where necessary (conversions, rendering annotations, etc.) in the context of every document PSPDFKit Server processes.

To create font substitutions that are scoped to a specific document and layer, see the API Reference for the font substitutions endpoint.

Please note that any substitutions for a document layer that are specified using the Font Substitutions API will be merged with the substitutions specified in font-substitutions.json before being applied.

If there are conflicts in the exact match patterns, then the substitutions that are specific to the document or layer will override the substitutions from font-substitutions.json. For example, if both the font-substitutions.json file and the Font Substitutions API are used to specify targets for the Roboto-Medium* pattern, then the target set through the API will override the target set in the font-substitutions.json file.