Configuring custom fonts for optimal PDF rendering
PSPDFKit Server has been deprecated and replaced by Document Engine. 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:
-
Clear the browser cache — This clears rendering artifacts cached by the browser.
-
Restart PSPDFKit Server — This clears the in-memory server cache for rendered pages.
-
Only if you use Redis — Delete the keys, starting with the
PSPDFKit-TileCache-
andPSPDFKit-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 pattern
s, 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.