TrueType Font in pdfTeX - V: Virtual Fonts, Ligatures, and OpenType
This blog is totally generated by LLM (I just check part of it)
In the previous post, TrueType Font in pdfTeX - IV, we loaded IBM Plex TrueType fonts in pdfTeX by creating a TeX font metric (.tfm), a LaTeX font definition (.fd), and a font map (.map). That was enough to typeset basic text, but several questions remained:
- How do we preserve ligatures, kerning, and the usual TeX conversions such as
--and---? - What should we do about missing characters reported by
ttf2tfm? - How can the same TTF files be used with XeLaTeX and LuaLaTeX?
- Is
autoinst/otftotfma better alternative tottf2tfm?
This post finishes those experiments. The focus remains on understanding the traditional TeX font machinery rather than simply installing a ready-made font package.
Scope. We are working with ordinary, static TrueType font files and the
T1text encoding. This is not a tutorial about variable-font axes, math fonts, or complex-script shaping. The IBM Plex file names used below are examples; check the exact names in your own download.
1. The font pipeline: TFM, VF, and map files
A useful distinction is between the font seen by TeX and the font ultimately embedded in the PDF.
1 | |
- TFM provides dimensions and the traditional TeX ligature/kerning program. TeX uses font metrics while breaking paragraphs; it does not need the glyph outlines at this stage.
- VF (virtual font) defines how a character in one TeX font is assembled from characters or rules in one or more physical fonts. A virtual glyph need not correspond to a single glyph in the source TTF.
- ENC supplies the mapping between the 8-bit character slots used by a physical TeX font and names of glyphs in the outline font.
- MAP tells the PDF backend how to find and embed the physical outline font. A virtual font is not itself an outline font to embed.
- FD tells LaTeX’s New Font Selection Scheme (NFSS) which TFM corresponds to a given encoding, family, series, and shape.
The distinction matters because ttf2tfm -v creates a raw TFM and a VPL (Virtual Property List). vptovf then converts the VPL into a virtual TFM and VF.
1.1 Why -T is not the whole story
Our earlier command was:
1 | |
In ttf2tfm, -T foo.enc is shorthand for specifying the same encoding as both the input/raw (-p) and output/virtual (-t) encoding. It does not, on its own, request a virtual font.
To generate the intermediate VPL, use -v:
1 | |
There are now two different metrics:
1 | |
Do not reuse the same font name for the raw and virtual TFM. The ttf2tfm manual explicitly warns about this.
The map entry must refer to the raw TFM:
1 | |
Meanwhile, the LaTeX .fd file selects T1-IBMPlexSerif-Regular (without -raw). The VF bridges the two.
2. Ligatures, kerning, and dashes
2.1 TeX ligatures are programs in the metrics
Traditional TeX handles ligatures and pair kerning while building the paragraph. Its TFM contains a small ligature/kerning program, which can be inspected in the human-readable PL/VPL representation.
For example, an illustrative PL fragment might contain:
1 | |
Here O 34 and O 35 are octal character slots for fi and fl in T1. The ligature is represented by a character slot in the TeX font; it does not require TeX itself to understand OpenType GSUB tables.
A kerning rule can look like:
1 | |
The value is illustrative, not an IBM Plex measurement. In a VPL with (DESIGNUNITS R 1000), the dimensions are given in thousandths of the design size; do not copy this value into a real font without checking it.
Inspect the generated files with:
1 | |
Do not assume that a command succeeded merely because the PDF compiles. An empty or incomplete LIGTABLE may mean the required font data was never imported.
2.2 The T1-WGL4.enc file contains more than a glyph list
One particularly useful feature of T1-WGL4.enc is its special % LIGKERN comments, which are understood by ttf2tfm:
1 | |
For example, the two-step replacement
1 | |
can be described by ligature rules in the font metrics. Similarly, `` and '' can become typographic quotation marks.
But there is an important condition: the target character must have a usable definition in the generated font. A rule referring to a missing ff character does not magically create an ff glyph. If ff, ffi, or ffl cannot be mapped, check which rules actually survived in the resulting VPL.
2.3 Why OpenType kerning may still be missing
TrueType/OpenType fonts may store kerning in either a legacy kern table or the newer GPOS layout table. Ligature substitution can likewise be defined through GSUB.
ttf2tfm can extract traditional TrueType metric/kerning information and process its own encoding-based ligature rules. It is not a full OpenType shaping engine; do not assume it will extract every GSUB/GPOS rule.
A practical consequence: a font may show kerning in XeLaTeX/LuaLaTeX but little or no kerning in a TFM created by ttf2tfm.
3. Missing characters: first diagnose, then fix
The warnings in Part IV included names such as:
1 | |
Not every warning has the same cause.
| Situation | Likely remedy |
|---|---|
| Glyph exists, but has a different name | Change the encoding or rename glyph mappings with ttf2tfm -r / -R |
| Glyph exists but is reachable only via GSUB | Use an OpenType-aware converter or an appropriate explicit mapping |
| Glyph is genuinely absent | Compose a virtual character, use a fallback, or edit the font |
| TeX-specific pseudo-character has no ordinary glyph | Implement the appropriate TeX-level behavior or virtual-font construction |
hyphen is mapped twice |
Recognize the encoding duplication warning; do not treat it as proof of a broken TTF |
3.1 Check Unicode mappings and OpenType tables
The Python package fontTools is useful here:
1 | |
1 | |
The cmap only answers whether a Unicode code point is mapped to a glyph. A ligature glyph might exist without a Unicode mapping, accessible only through GSUB. Therefore, absence from getBestCmap() is not conclusive evidence that the glyph is absent from the font.
For a more direct OpenType feature inventory, use:
1 | |
3.2 Compose a missing character in a virtual font
A VF can assemble one logical TeX character from several physical glyphs. Suppose we want a fallback ff character, but the physical TTF provides only f.
A schematic VPL definition (T1 slot O 33 is ff) is:
1 | |
This is not a drop-in patch: the character dimensions are placeholders; the selected raw font must have a usable f at that slot; any advance adjustments or kerning must be calculated; and the corresponding LIGTABLE entry must refer to the constructed ff character. Preserve the generated VPL’s other records, especially MAPFONT and existing ligature rules.
After editing the VPL, regenerate the VF and virtual TFM:
1 | |
This fallback makes the two f glyphs act as one TeX character, but it does not recreate a type designer’s original ff ligature outline. It can also have limitations for copy/paste and Unicode extraction from the PDF. Prefer mapping to an authentic glyph when possible.
4. Batch conversion for my actual directory layout
I now keep the fonts in two subdirectories:
1 | |
The following Bash script processes every matching TTF in each directory. It writes the generated metrics and virtual fonts into the project root, along with one shared ibmplex.map.
font_trans_batch.sh:
1 | |
Run:
1 | |
A typical map entry now looks like:
1 | |
The subdirectory path is important. For a local experiment, compile the test document from the project root so that the map, metrics, VFs, and referenced TTF paths can all be found. For a system-wide installation, use a proper TEXMF directory structure instead.
Caution: This script discovers additional weights such as Light and Medium, but the .fd definitions below deliberately select only four styles. Converting a font and registering it with NFSS are separate operations. Also, regenerating VPLs overwrites manual edits, so save customized VPLs separately.
5. Two LaTeX font families: Serif and Mono
NFSS expects a font definition file named after the lower-case encoding and family. I will use:
1 | |
Rather than treating sans-serif or monospace as a non-standard font shape, make each family independent. In standard NFSS terminology, shape n means upright and it means italic; the mono/serif distinction belongs to the family.
5.1 t1ibmplexserif.fd
1 | |
5.2 t1ibmplexmono.fd
1 | |
The bx substitution declarations make \textbf work even when our physical font series is registered as b. Also notice that I removed the old \hyphenchar\font=-1 family declaration; that setting would disable automatic hyphenation, which is normally undesirable for serif body text.
5.3 A pdfLaTeX test
1 | |
Compile and inspect the result:
1 | |
A successful compilation does not guarantee that all glyphs appeared correctly. In particular, check PDF font warnings and visually compare fi, fl, the other f-ligatures, and the dashes.
6. XeLaTeX and LuaLaTeX: no TFM/VF conversion is needed
For these engines, the ordinary route is fontspec, which can load the TTF directly and use the modern font-loading/shaping infrastructure.
In our directory layout:
1 | |
The most relevant features are:
fontspec setting |
Purpose |
|---|---|
Ligatures=Common |
Enable ordinary OpenType liga substitutions where available |
Ligatures=TeX |
Request the traditional TeX-style quote/dash input mappings |
Kerning=On |
Enable available font kerning |
Do not confuse Ligatures=TeX with the OpenType liga feature: the former provides TeX-like input substitutions, while the latter selects typographic glyph substitutions. The exact outcome still depends on the font and renderer. For source-code text, you may prefer not to enable TeX punctuation substitutions in the mono font.
You do not need \pdfmapfile, ttf2tfm, or custom .fd files in this example. LuaLaTeX also does not need the old compatibility workaround \protected\def\pdfmapline{\pdfextension mapline } merely to load a Unicode TrueType font.
Traditional TeX fonts can still be used with XeTeX/LuaTeX, but that is a different, legacy route and not the reason to choose fontspec.
7. ttf2tfm versus otftotfm versus autoinst
The official plex package is a useful comparison. Its documentation says that its Type 1 fonts were made with cfftot1, and its LaTeX support files with autoinst.
The distinction is important: autoinst is not itself a TrueType-to-Type-1 converter. It is an automation layer around the LCDF TypeTools, most importantly otftotfm.
1 | |
7.1 Capabilities
| Property | ttf2tfm |
otftotfm / autoinst |
|---|---|---|
| Original purpose | Convert TrueType metrics to TeX | Convert OpenType fonts and build LaTeX support |
| TrueType outlines | Yes | Supported by otftotfm, but some versions warn that support is experimental |
| CFF-based OpenType input | Not its main input format | Yes |
| TFM and virtual fonts | Yes, via VPL and vptovf |
Yes |
| Traditional TeX ligature rules | Via encoding directives and TFM | Yes |
| GSUB/GPOS feature extraction | Limited | More capable, depending on supported feature/lookup |
Generate .fd and .sty |
Handwritten | Automated by autoinst |
| Best for | Learning and manual control | Repeatable font-package generation |
The table is deliberately not a claim that otftotfm performs all modern shaping. The 8-bit TFM/VF model still has intrinsic limitations, and some OpenType features cannot be faithfully represented by a static conversion.
7.2 Inspect OpenType features
First check which features are actually present:
1 | |
Useful tags include liga (standard ligatures), kern (kerning), smcp (small caps), onum (oldstyle figures), and tnum (tabular figures). Feature availability is font- and style-dependent. Do not request a feature and assume it exists just because the command accepts the option.
An otftotfm experiment with a TTF might look like:
1 | |
The fontools_t1 encoding is shipped with the fontools package. Unlike ttf2tfm, otftotfm requires an explicit encoding for TrueType-flavored input, and some installed releases report: TrueType-flavored font support is experimental. The exact features available depend on the version of LCDF TypeTools and the font.
7.3 Try autoinst without modifying the TeX installation
For a controlled experiment, use its manual mode:
1 | |
Manual mode is intentionally multi-step. First, autoinst analyzes font metadata and writes an autoinst.bat file containing the proposed otftotfm commands. It does not immediately execute all of those commands. Inspect the log and commands before proceeding:
1 | |
After reviewing the commands, run each autoinst.bat from its own directory, and follow the manual-mode instructions to turn generated PL/VPL files into TFM/VF and register the map if you want a permanent installation. This keeps the experiment separate from the system TEXMF tree.
One benefit of autoinst is that it automatically discovers the available weights, italic shapes, and some optional OpenType features, then generates NFSS definitions rather than requiring us to maintain many nearly identical .fd files by hand.
8. Suggested verification checklist
- Confirm that the input TTF, encoding file, raw TFM, virtual TFM, and VF are all discoverable by TeX.
- Check that map entries refer to the raw font name and the correct TTF path.
- Inspect
LIGTABLEandKRNentries rather than relying on visual appearance alone. - Test
fi,fl,ff,ffi,ffl,--,---, and quotation marks. - Compare the same test in pdfLaTeX, XeLaTeX, and LuaLaTeX.
- Read both the LaTeX log and the PDF embedding information from
pdffonts. - Compare the results with the official
plexpackage or anautoinst-generated font package.
Conclusion
The three remaining tasks from Part IV lead to a useful distinction:
ttf2tfm+vptovfis a good way to learn how TeX’s metrics, ligature tables, and virtual fonts work. It gives us direct control but also makes missing glyphs and incomplete OpenType feature extraction our responsibility.otftotfm+autoinstis a higher-level way to generate traditional TeX font support from OpenType fonts, with better access to available GSUB/GPOS information and much less handwritten NFSS boilerplate.fontspecis the natural choice when compiling with XeLaTeX or LuaLaTeX: no 8-bit conversion pipeline is needed for these TTF files.
For this blog series, I will keep the ttf2tfm route as an educational experiment, while treating the generated files from autoinst as a useful reference implementation. The next interesting question is precisely how OpenType GSUB/GPOS information is approximated by TeX’s LIGTABLE, TFM metrics, and virtual-character mappings.
References
ttf2tfmmanual — raw and virtual encodings,-T,-v, glyph mapping and ligature rules.vptovfmanual — converting VPL to VF and TFM.- LCDF TypeTools (
otftotfm) — TeX metrics from OpenType fonts. autoinstmanual / fontools — automated generation of font support files and manual mode.fontspecdocumentation — OpenType features under XeLaTeX and LuaLaTeX.- CTAN:
plex— the existing IBM Plex LaTeX distribution and its Type 1 /autoinstapproach. - IBM Plex source and releases — upstream fonts and licensing.
- fontTools documentation — inspecting
cmap, GSUB, GPOS, and other font tables.