Skip to main content

Font handling

Font configuration is per use case: five independent mechanisms, each with its own rules, several of them sharing one directory. Pick the row that matches what you want to change, then follow the matching section.

What you want to changeWhere the files goProperty
The typeface used when a PDF does not embed its own font, as seen in the viewerThe shared font directory, one file named after each font a document asks forNone. See Displaying a document
The fonts available to annotation text drawn into a documentThe same directory by default, or wherever document.font.path pointsdocument.font.path, annotation.textual.unicode.font.path. See Fonts for annotation text
The fonts available when producing PDF/A outputThe same directory by default, or wherever document.font.path points, read by a separate scandocument.font.path, document.font.allowed.extensions. See Fonts for PDF/A output
The font used when a text file is converted to PDFAny path you choosetext.to.pdf.font.family, text.to.pdf.font.file.path. See Fonts for text-to-PDF conversion
The fonts used by the office conversion toolsSystem font directories inside the converter imageNone. See Fonts used by the conversion tools

The properties above all belong to the document-converter service. The rendering engine reads the shared font directory as well, but takes no property: its path is built in. The viewer has font settings of its own, which choose the family an annotation asks for rather than the font files available to satisfy it.

The names are Spring Boot properties. In Docker and Kubernetes the same settings are passed as environment variables carrying the converter prefix, so document.font.path is set as DCV_DOCUMENT_FONT_PATH, see Property-to-variable mapping rules.

Displaying a document

A PDF that embeds its fonts is displayed with them, and nothing has to be configured. When a PDF names a font without embedding it, the rendering engine substitutes one, so text is always readable: real glyphs are drawn, never blank space and never empty boxes.

You can choose the substitute. Put the font in the shared font directory and name the file after the font the PDF asks for: a document referencing /ReproFontXYZ is rendered with ReproFontXYZ.ttf.

DeploymentShared font directory
Spring Boot standalonemodules/fonts/, next to the module directories. Ships with Times.ttf
Docker, Kubernetes/fonts in the document-renderer container, to be mounted. The converter reads whatever document.font.path points at, so in Docker these are two separate mounts

The path is ../fonts/ relative to the renderer working directory, built into the rendering engine, and no property changes it. Restart the renderer after adding a file.

With no matching file, the engine picks a face from the font name: TimesNewRomanPSMT, Courier or Arial give a serif, monospace or sans-serif face, and an unrecognized name gives a generic sans-serif.

One directory, two matching rules

In a Spring Boot standalone install this is also where document.font.path points by default, so a single modules/fonts/ serves everything. The mechanisms stay independent, and they do not look a font up the same way:

MechanismFont matched on
Display substitutionThe file name, which has to be the name the document asks for
Annotation text, PDF/A outputThe font name declared inside the file, so renaming a file changes nothing

document.font.path is a converter setting, described below, and it reaches only files the converter produces: the fonts offered to annotation text, and the fallback for a font the source PDF does not embed when a PDF/A is built. Displaying a page does not go through the converter, so that property changes nothing in the viewer. It was called document.fallback.font.path in ARender 4.8.

Fonts for annotation text

Annotations are drawn into the document whenever the converter produces a file that carries them: download or print with annotations, download with redactions applied or with rotations, the redacted copy, the crop-box snapshot, the Document Builder save, and any output with a watermark. Which of these a viewer offers varies.

The properties below reach only part of that text:

TextFont used
Sticky note, free text, and the popup note of a highlight, strikeout, underline or text redactionA family match in document.font.path, or the file in annotation.textual.unicode.font.path when it is set
Stamp text, watermark text, measure-line length labelStandard Helvetica, not configurable
Redaction overlay textStandard Times-Roman, not configurable

document.font.path is the directory of fonts offered to annotation text: a font placed here is used when an annotation asks for its family by name. It is re-scanned every time annotations are drawn.

AspectBehavior
Accepted files.ttf and .TTF only. document.font.allowed.extensions does not apply here, so OpenType files and mixed-case extensions such as .Ttf are ignored
Family nameThe family declared inside the file. An annotation is drawn with it only when it asks for that family, and what it asks for is decided in the viewer
ScanEvery file is parsed on every document, subdirectories and symbolic links included. Keep the directory small and flat
Empty valueResolves to the converter working directory and walks that whole tree. Set the property explicitly
Unreadable directoryWarning Can't parse font directory, and the export still completes with the standard PDF fonts, which cover Latin-1 only

annotation.textual.unicode.font.path is how you cover a script the standard PDF fonts cannot encode, Chinese for instance. It names one font file and draws all annotation text with it.

AspectBehavior
When to set itAnnotation text written in Chinese, Japanese, Korean, Arabic, Hebrew, Cyrillic or Greek. A font dropped in document.font.path is not enough on its own: it is used only if the annotation asks for that family, and the viewer decides what is asked
PathThe full path of one font file. Keep that file in the document.font.path directory, so that a single mount covers both settings: /arender/fonts/NotoSansSC-Regular.ttf with the mount shown under Docker and Kubernetes. Any other absolute path works, as does a path relative to the converter working directory
EffectThe file is embedded, and every family the annotation asks for is replaced by it, so all annotation text, Latin included, is drawn with this one font
Fonts from the directoryStill scanned and still registered, but no longer requested, so they stop appearing in annotation text
Accepted fileTrueType only. An OpenType file built on CFF outlines fails the export with True Type fonts using CFF outlines are not supported

Fonts for PDF/A output

PDF/A conversion runs only when pdfa.controller.enabled is true, on the converter and on the broker. With the default, a request returns 404.

Each page of the produced PDF/A is an image of the page, with an invisible text layer on top. That layer is the only reason the archive stays searchable and its text selectable, and a character reaches it only if a font can encode it. Fonts therefore decide how much of the text survives the conversion, never how the page looks.

Each character is drawn with, in order:

  1. The font embedded in the source PDF
  2. A file from document.font.path whose internal name matches the font the PDF asks for
  3. Standard Helvetica

A character none of the three can encode is left out of the layer. Converting a Chinese document with no CJK font available gives a PDF/A that looks perfect, returns nothing when searched, and copies as nothing.

Step 2 reads the same document.font.path directory as annotation text, with its own rules on which files count and how they are named:

AspectBehavior
Accepted filesExtensions from document.font.allowed.extensions, ttf,otf by default, and that property applies to this scan only. Prefer TrueType: an OpenType file built on CFF outlines cannot be registered, one carrying TrueType outlines loads normally
Font nameThe name a font file carries inside itself, its PostScript name, which is unrelated to the file name: the malgun.ttf shipped in the converter image declares MalgunGothic. That internal name is what gets matched against the font the PDF asks for, so renaming a file changes nothing
DuplicatesKeep one file per font name. If two files declare the same name, which one is used is not defined
ScanSubdirectories at any depth are included. A file whose extension is not in the list is logged at INFO, a file that cannot be parsed at ERROR, and is not registered
After a changeNew files are picked up on the next conversion. Restart the converter after removing or replacing a file: the name-to-file table is kept for the lifetime of the service

Fonts for text-to-PDF conversion

Converting a plain text file to PDF uses its own font settings and never reads document.font.path.

PropertyDefaultNotes
text.to.pdf.font.familyCOURIERExactly five values, upper case, matched literally: COURIER, HELVETICA, TIMES_ROMAN, SYMBOL, ZAPFDINGBATS. Bold and oblique variants are not accepted. Any other value fails every text conversion with Not acceptable font family name <value>, and the converter reports itself unhealthy at start-up
text.to.pdf.font.size13Points
text.to.pdf.landscapetruePages are A3, so the default is A3 landscape
text.to.pdf.font.file.pathemptyA single TrueType file, embedded as a subset. When set, text.to.pdf.font.family is not used. An unreadable path is logged as Could not load font <path> and the family above is used instead
Check that the font covers your documents

Characters the font has no glyph for are omitted from the output, with no box and no question mark, so a page can look complete while text is missing. The standard PDF fonts cover Latin-1: accented Latin is fine, while Arabic, Hebrew, Cyrillic, Greek and CJK need a font supplied through text.to.pdf.font.file.path. SYMBOL and ZAPFDINGBATS are meant for their own character sets and drop ordinary Latin text.

Two limits when supplying your own file:

  • Use a single-font TrueType file. A TrueType Collection (.ttc) cannot be parsed and the conversion fails with 'head' table is mandatory.
  • Text is drawn in logical order, without complex-script shaping or bidirectional reordering. Arabic and Hebrew come out as unjoined letters in reverse reading order even with a font that has the glyphs. CJK, Cyrillic and Greek are unaffected.

Fonts used by the conversion tools

Office conversion relies on third-party tools that read fonts from the operating system, not from any ARender property. In the document-converter image these live under /usr/share/fonts/TTF/, where the Chinese and Korean fonts shipped with ARender are installed, plus the font packages and bundled tool directories of the image. Install fonts needed for office conversion there, not in document.font.path.

CAD conversion has its own SHX font mechanism. See CAD conversion.

Where to put the files

Spring Boot standalone

modules/fonts/ sits next to the module directories, and both services resolve ../fonts/ to it: the renderer from modules/PDFOwl/ or modules/JNIPdfEngine/, the converter from modules/TaskConversion/. One directory therefore serves display substitution, the annotation scan and the PDF/A scan at once, each with its own matching rule.

Point document.font.path elsewhere and the two converter scans follow it, while display substitution stays on modules/fonts/.

Docker and Kubernetes

The images have no modules/ layout and none of them creates a font directory, so document.font.path must be set explicitly. Mount your fonts and point the property at the mount target:

docker-compose.yml
services:
document-converter:
image: artifactory.arondor.cloud:5001/arender-document-converter
volumes:
- ./fonts:/arender/fonts:ro
environment:
- "DCV_DOCUMENT_FONT_PATH=/arender/fonts"
# Only for annotation text in a non-Latin script, see above
# - "DCV_ANNOTATION_TEXTUAL_UNICODE_FONT_PATH=/arender/fonts/NotoSansSC-Regular.ttf"

Display substitution runs in another container, and its path does not come from a property, so it needs its own mount: attach a font directory at /fonts on document-renderer, with one file named after each font a document asks for, as described in Displaying a document.