ksTFL renders DOCX documents using a C++ engine that requires TrueType/OpenType font files for text measurement and pagination. The package automatically discovers fonts installed on the operating system at load time. If a required font is not available on the system, a metrically compatible open-source fallback is used.
This guide explains how font discovery works, which fallback fonts are bundled, and how to configure custom font directories.
When ksTFL is loaded, it performs four steps:
Scan system directories. The C++ font scanner
walks the platform-specific directories recursively and reads family
names and style flags from .ttf, .otf, and
.ttc files. For a given family and style the first file
found wins, which is why earlier-scanned directories take
priority.
Scan user directories. If the R option
ksTFL.font_dirs is set, those directories are scanned as
well.
Scan bundled fallbacks. The package’s own
inst/fonts/ directory is scanned last.
Resolve target fonts. For each target family (Arial, Times New Roman, Courier New, Georgia, Verdana, Trebuchet MS), ksTFL keeps the discovered font when available or assigns a designated fallback.
Key rule: system-installed fonts always take priority. The bundled fallbacks are only used when a target font is not found anywhere on the system.
The scanner inspects the following directories by default:
| Platform | Directories |
|---|---|
| Linux | /usr/share/fonts, /usr/local/share/fonts,
~/.local/share/fonts, ~/.fonts, plus the
fonts/ subdirectory of each $XDG_DATA_DIRS
entry |
| macOS | /System/Library/Fonts,
/System/Library/Fonts/Supplemental,
/Library/Fonts, ~/Library/Fonts |
| Windows | System fonts directory (from the OS API; typically
C:\Windows\Fonts), plus user fonts in
%LOCALAPPDATA%\Microsoft\Windows\Fonts |
The rendering engine targets six font families commonly used in clinical documents. Each has a metrically compatible open-source fallback bundled with the package:
| Target Font | Fallback Font | Notes |
|---|---|---|
| Arial | Liberation Sans | Metrically identical to Arial |
| Times New Roman | Liberation Serif | Metrically identical to Times New Roman |
| Courier New | Liberation Mono | Metrically identical to Courier New |
| Georgia | Liberation Serif | Serif fallback for Georgia |
| Verdana | Liberation Sans | Sans-serif fallback for Verdana |
| Trebuchet MS | Liberation Sans | Sans-serif fallback for Trebuchet MS |
All bundled fonts are licensed under the SIL Open Font License 1.1.
The R layer accepts only these seven families in
s_font(font_name = ...): the six targets above plus
Liberation Sans. If the renderer encounters a family it
cannot resolve on disk (possible only in a hand-edited spec or template
JSON), it falls back to the bundled Liberation Sans.
For convenience, ksTFL also registers built-in style names for the
target families: font_arial, font_courier_new,
font_times_new_roman, font_georgia,
font_verdana, and font_trebuchet_ms. These are
strings you pass to style slots (labelStyleRef,
valueStyleRef, styleRef) or to
f_combine(); each sets only font_name, so they
combine safely with size, colour, alignment, and other style atoms.
After loading the package, call tfl_font_status() to see
the current font resolution:
library(ksTFL)
tfl_font_status()
#> ksTFL font scan: 3 target(s) resolved, 3 using fallback
#> [ok] Arial -> Arial
#> [ok] Times New Roman -> Times New Roman
#> [ok] Courier New -> Courier New
#> [fallback] Georgia -> Liberation Serif
#> [fallback] Verdana -> Liberation Sans
#> [fallback] Trebuchet MS -> Liberation Sans
#> Scanned 5 directoriesThe counts depend on which proprietary fonts are installed and how many font directories exist on your machine; the report always lists all six targets with their resolution.
Reading the output:
[ok] — The target font was found on
the system and will be used directly.[fallback] — The target font was not
found; the bundled fallback is used instead.(not found) — Neither the family nor
its fallback resolved on disk (rare; usually a broken or unreadable font
file).If proprietary fonts are installed in a non-standard location (e.g.,
a network share or a project-local folder), point the
ksTFL.font_dirs option to those directories
before loading the package, or rescan afterwards:
This works only when the option is set before ksTFL is first loaded in the session; if the package is already loaded, use Option B.
Call tfl_rescan_fonts() after:
ksTFL.font_dirs option# Install Georgia to /usr/local/share/fonts/georgia/ ... then:
tfl_rescan_fonts()
#> ksTFL font scan: 1 target(s) resolved, 5 using fallback
#> [fallback] Arial -> Liberation Sans
#> [fallback] Times New Roman -> Liberation Serif
#> [fallback] Courier New -> Liberation Mono
#> [ok] Georgia -> Georgia
#> [fallback] Verdana -> Liberation Sans
#> [fallback] Trebuchet MS -> Liberation Sans
#> Scanned 6 directoriesA machine shows all six [ok] only when every proprietary
family is actually installed (Windows workstations typically are; bare
Linux servers typically are not).
When the package is attached, it prints a concise summary if any target fonts are using fallbacks:
ksTFL v0.12.0 - Clinical TFL Framework
For help, type: ??ksTFL
Note: 3 font(s) using fallback: Georgia, Verdana, Trebuchet MS
Run tfl_font_status() for details.
If all target fonts are found on the system, no font-related message is shown.
write_doc()write_doc() uses the font directories from the scanner
cache. You can pass additional per-call directories via its
font_dirs argument:
write_doc(report, name = "output",
outDir = "results",
metaPath = tempdir(),
font_dirs = "/path/to/extra-fonts")Per-call directories are appended to the scanner’s cached list for
that render only — they do not modify the global font registry.
replay_report() uses the same cache but has no
font_dirs argument; register extra directories with
options(ksTFL.font_dirs = ...) plus
tfl_rescan_fonts() before replaying.
[fallback] for a font I know is installed.
What’s wrong?The font may be installed in a directory not scanned by default. Add
its directory to ksTFL.font_dirs and rescan:
Not in s_font(). The R layer accepts exactly seven
families: Arial, Courier New, Times New Roman, Georgia, Verdana,
Trebuchet MS, and Liberation Sans. Fonts the scanner discovers outside
this set are visible to the internal resolver but cannot be named in a
spec — pick the closest allowed family. The scanning directories still
matter for the six target families: if one of them lives in a
non-standard directory, add that directory to
ksTFL.font_dirs so the resolver finds the real font instead
of the fallback.
The fallback fonts (Liberation family) are designed to be metrically compatible with their proprietary counterparts. Line breaks, page breaks, and column widths should be identical or very close. Minor glyph-level differences may exist, but document layout is preserved.