Configure fonts¶
When EPPlus renders text to the HTML/SVG and PDF exports, it measures and shapes the text using real
font data. EPPlus ships with sensible defaults, including built-in fallbacks for missing fonts and
characters, so in most cases you don't need to configure anything. When you do,
Workbook.ConfigureFonts lets you control where fonts are loaded from, how missing fonts and
characters are handled, and how fonts are embedded in PDF files.
Font configuration is applied per workbook and must be set before you export. It does not affect any other workbook or any global state.
Default behaviour¶
If you never call ConfigureFonts:
- Fonts are searched for in the operating system's standard font directories.
- A missing font is replaced using EPPlus's built-in fallback chains, which prefer metric-compatible substitutes such as Carlito for Calibri. If none is available, the embedded Archivo Narrow font is used, so a missing font never causes an export to fail.
- Characters that the font lacks, for example Japanese text in a Latin font, are taken from per-script fallback fonts when these are installed. Emoji and mathematical symbols always come from the bundled Noto Emoji and Noto Math fonts.
The export always succeeds, but the result is not always the intended one. Text in a writing system
for which no font is available is drawn with missing-glyph boxes. To render, for example, Chinese,
Japanese or Korean text on a server, make sure a font for the script is installed or supplied through
FontDirectories.
How the fallbacks work, and the complete list of built-in chains, is described in Font fallbacks.
Configuring fonts¶
Call ConfigureFonts on the workbook and change the configuration inside the callback. The example
below adds a font directory and turns off the system font search, so that only fonts from your
directory are used:
The changes you make inside the callback are applied as a single transaction: when the callback returns, the font resolver is rebuilt and the workbook's font caches are cleared.
These are the members you can use inside the callback:
| Member | Data type | Description |
|---|---|---|
FontDirectories |
IList<string> |
Additional directories to search for font files, beyond the system font directories. |
SearchSystemDirectories |
bool |
Whether the operating system's standard font directories are searched. Defaults to true. Set to false to use only FontDirectories. |
FontFallbacks |
IDictionary<string, string[]> |
Your own fallback chains, mapping a font name to the fonts to try when it is missing. Tried before the built-in chains. See Font-level fallback. |
SetScriptFallback(...) |
method | Replaces the fallback chain for a Unicode script, used for characters the font lacks. See Script-level fallback. |
WebFontSubstitutions |
IDictionary<string, string> |
Fonts substituted in the HTML and SVG exports, for fonts that browsers can't use, such as Aptos. See Web font substitution. |
MetricsFallback |
MetricsFallbackMode |
When text is measured with serialized font metrics instead of a font file. See Measurement without the font. |
OnFontEmbedding(...) |
method | Decides how fonts are embedded in PDF files. See Embedding restrictions. |
Logger |
IFontLogger |
Receives reports about font resolution, fallbacks and embedding. See Finding out which fonts were used. |
FontResolver |
IFontResolver |
Replaces the font resolver entirely. See Custom font resolution. |
Reset() |
method | Restores the default configuration, including the built-in script chains and web font substitutions. |
Common configurations¶
Fonts on a server or in a container¶
Servers and containers often have few fonts installed. Either install the fonts the workbooks use, or ship them with your application and add their directory:
If you can't distribute the original fonts, the metric-compatible open fonts Carlito, Caladea and the Liberation family are used automatically by the built-in fallback chains when they are available. They keep column widths and line breaks close to the original.
A fallback for your own font¶
A font for a writing system¶
Setting a chain replaces the built-in chain for that script completely. Pass no font names to turn off fallback for a script.
Embedding restrictions¶
When EPPlus embeds a font in a PDF it subsets the font by default: only the glyphs actually used are
included, which keeps the file small. Fonts declare, through their OS/2 fsType field, whether and
how they may be embedded. EPPlus honours those declarations:
- Installable, Preview & Print, or Editable embedding: the font is subsetted and embedded normally.
- No subsetting: the font may be embedded, but not as a subset. EPPlus embeds the complete, unmodified font instead. This produces a larger PDF but respects the font's terms.
- Restricted License: the font declares that it must not be embedded at all. By default EPPlus throws an exception rather than silently embedding a font you may not have the right to embed.
The fsType field is the font vendor's declaration; it is not a technical lock. If you hold a
licence from the font's owner that permits embedding, regardless of what fsType says, you can
override EPPlus's default handling with OnFontEmbedding:
package.Workbook.ConfigureFonts(Sub(cfg)
cfg.OnFontEmbedding(Function(info)
' You have licensed "Acme Display" for embedding.
If info.FontName = "Acme Display" Then
Return FontEmbeddingDecision.Subset
End If
' Everything else follows EPPlus's default handling.
Return FontEmbeddingDecision.Default
End Function)
End Sub)
The callback is invoked once per font about to be embedded and receives a FontEmbeddingInfo
describing the font: its FontName and the Restriction it declares (a FontEmbeddingRestriction
of None, NoSubsetting or NoEmbedding). You can inspect the declared restriction and decide
accordingly, for example keeping restricted fonts out of the PDF entirely rather than failing the
export:
package.Workbook.ConfigureFonts(cfg =>
{
cfg.OnFontEmbedding(info =>
{
// We hold no licence for restricted fonts, so keep them out of the PDF
// and let the fallback chain render their text instead.
if (info.Restriction == FontEmbeddingRestriction.NoEmbedding)
return FontEmbeddingDecision.Skip;
// Everything else follows EPPlus's default handling.
return FontEmbeddingDecision.Default;
});
});
package.Workbook.ConfigureFonts(Sub(cfg)
cfg.OnFontEmbedding(Function(info)
' We hold no licence for restricted fonts, so keep them out of the PDF
' and let the fallback chain render their text instead.
If info.Restriction = FontEmbeddingRestriction.NoEmbedding Then
Return FontEmbeddingDecision.Skip
End If
' Everything else follows EPPlus's default handling.
Return FontEmbeddingDecision.Default
End Function)
End Sub)
Return one of:
| Decision | Effect |
|---|---|
Default |
Follow EPPlus's standard handling for the font's declared restriction (throw for Restricted License, embed whole for no subsetting, subset otherwise). |
Subset |
Subset and embed the font, regardless of fsType. |
EmbedWhole |
Embed the complete font without subsetting. |
Skip |
Do not embed the font; its text is rendered with the fallback chain instead (ultimately the last-resort font, Archivo Narrow). Lets you keep a font out of the PDF without failing the export. |
You are responsible for compliance
Returning Subset or EmbedWhole for a font that restricts embedding asserts that you hold the
necessary rights. EPPlus cannot verify any licence you may have obtained and does not check on
your behalf.
Fonts bundled with EPPlus (Archivo Narrow, Noto Emoji and Noto Math) are always subsetted and embedded.
Custom font resolution¶
The font pipeline is built around interfaces, so its parts can be replaced when the built-in
behaviour isn't enough. Most notably, you can supply your own font resolver: implement
IFontResolver (OfficeOpenXml.Interfaces.Fonts) and assign it to FontResolver to take full
responsibility for producing font data, for example to load fonts from a database or an embedded
resource instead of the file system.
A custom resolver replaces the whole font-level fallback, including the built-in chains and the last-resort font. Script-level and glyph-level fallback still apply, and the fonts in the script chains are loaded through your resolver. Keep in mind:
- Return a font for every request. Archivo Narrow, the last-resort font, is part of EPPlus's own
resolver and is not used with a custom one. If your resolver can't find a font, return a default
font of your own rather than
null. - Implement
IFontAvailabilityProvideras well, if your resolver substitutes fonts internally. EPPlus uses it to check whether a font in a script chain is really available. Without it, EPPlus can only check that the resolver returns some font, so every font in a chain looks available and the chain is not walked as intended.
Which exports use the font configuration¶
Font configuration affects the exports that measure and shape text against real font data:
- HTML/SVG export: charts and shapes rendered to SVG.
- PDF export.
Other operations, such as saving the workbook as an .xlsx file, are not affected by this
configuration.