Skip to content
danfickle edited this page May 25, 2020 · 5 revisions

Notes on fonts for PDF document generation

  • Embedded fonts must be TrueType (.ttf).
  • OpenType fonts are not supported due to PDF-BOX not supporting them.
  • Italic font style (italic) and bold font weights may be emulated if a font is not provided for bold and/or italic versions. The emulation is achieved by stroking/stretching the normal font version. This may or may not provide acceptable results. The small-caps font variant is not emulated.
  • If the correct style, weight or variant is not found, and can't be emulated (eg. going from a bold font to normal weight) a closest match will be used.
  • Comma separated font fallback is supported. This can be useful for example with mixed language text. When no PDF/A conformance is required a final fallback serif PDF built-in font will be used.
  • If no glyph is found for a character in any of the specified fonts (plus serif) the behavior is as follows. Control character codes will be ignored, whitespace characters will be replaced with the space character and any other character will be replaced with the replacement character (# by default).
  • PDF has built in fonts (serif, sans-serif, monospace). The fonts only support a basic Western European character set and it is now usually recommended that you embed fonts that you wish to use. Setting PDF/A conformance will stop these fonts being used and an embedded font must be provided and set on the body element.
  • Google Fonts is a good source of open-source fonts, especially the noto family.
  • Relative font weights (bolder, etc) are not implemented.
  • Symbol fonts such as FontAwesome can be used, but may need tweeks (such as removing font-face imports other than TrueType) to their associated CSS files to get working.
  • Embedded fonts are subset by default. This is typically the correct behavior, except for fonts used with form controls. You can avoid subsetting by using the -fs-font-subset: complete-font property in a @font-face block or programatically by setting the subset parameter to false.
  • The font-family property is inherited. Therefore, you have to be very careful to make sure that form controls do not inherit a subset font.
  • Fonts may be added for embedding via CSS @font-face blocks or programatically via the builder.
  • A font metrics cache can be specified with the builder. This will mean that if the font metrics are in the cache and a fallback font is not needed that the font will not be loaded. The font metrics value is immutable and thread safe so a multi-thread cache may be used.

Programatically adding fonts

// Uses the shorthand method, assumes normal weight and style and subset set to true.
builder.useFont(new File("/path-to-fonts/fonts/JustAnotherHand.ttf"), "hand");

// Longhand method
builder.useFont(new File("/path-to-fonts/fonts/NotoNaskhArabic-Bold-Italic.ttf"), "arabic-bold-italic", 700, FontStyle.ITALIC, /* subset: */ true);

// Use a font metrics cache to avoid loading fallback fonts each run.
builder.useCacheStore(CacheStore.PDF_FONT_METRICS, cache);

CSS font embedding example

This example shows using all four of the Noto Serif (by Google) font types:

<html>
<head>
<style>
@font-face {
  font-family: 'noto';
  /* Note: No trailing format tag is allowed. */
  src: url(fonts/NotoSerif-Regular.ttf);
  font-weight: normal;
  font-style: normal;	
}
@font-face {
  font-family: 'noto';
  src: url(fonts/NotoSerif-Bold.ttf);
  font-weight: bold;
  font-style: normal;	
}
@font-face {
  font-family: 'noto';
  src: url(fonts/NotoSerif-BoldItalic.ttf);
  font-weight: bold;
  font-style: italic;	
}
@font-face {
  font-family: 'noto';
  src: url(fonts/NotoSerif-Italic.ttf);
  font-weight: normal;
  font-style: italic;	
}

.noto {
  font-family: 'noto', serif;
}
.bold {
  font-weight: bold;
}
.italic {
  font-style: italic;	
}
</style>
</head>
<body>
<p class="noto">Regular Noto Font</p>
<p class="noto bold">Bold Noto Font</p>
<p class="noto italic">Italic Noto Font</p>
<p class="noto italic bold">Bold Italic Noto Font</p>
</body>
</html>

SVG fonts

  • Currently, if using the SVG support plugin, all fonts from @font-face blocks will be additionally loaded for use by the SVG graphics. Programatically added fonts are not used by SVG.

MathML fonts

  • If using the MathML support plugin, fonts specified in any math element's font-family style and provided by @font-face blocks will be additionally loaded for use by MathML objects. Programatically added fonts are not used for MathML.
  • It is recommended that the STIX fonts package be used for MathML objects. Download STIX fonts in TrueType format.

Font performance tips

  • Prefer to programatically add fonts with the builder methods that take a File. Providing a File directly means that the entire file may not have to be read to parse the font.
  • Always use a font metrics cache if performing multiple runs with the same fonts.
  • Specify font families in the font-family style property from most used to least used. This will mean that lesser used fonts do not always have to be loaded (provided a font metrics cache is present). Take this example - font-family: 'english', 'chinese', 'korean';. The Chinese font will only be loaded if there are characters in the document not present in the English font and the Korean font will not be loaded unless the characters aren't present in English or Chinese.

Java2D font handling

  • Currently, Java2D only supports ttf files. They can be specified programatically or via @font-face blocks. If you want to use fonts from the environment: builder.useEnvironmentFonts(true). Be careful with environment fonts, you may get different results depending on what fonts are available.

Open issues

  • Text justification support needs manual merge from 143 Implemented in RC15.
  • We need to unify the font loading and embedding as far as possible across PDF, SVG and MathML.
  • Add programmatic methods to add fonts for Java2D renderer. Implemented in 1.0.3.
  • Support OpenType when/if PDF-BOX/FONT-BOX do.