Font tools

Most authors never touch a .vf file by hand. But once you start building or wiring up fonts, you need three power tools: the virtual font that bridges a logical font onto real ones, the JFM (Japanese Font Metric) that records CJK glyph widths and punctuation spacing, and the glyph-table tools that show you what a font actually contains. This page covers those low-level utilities, aimed at font developers and power users.

Virtual fonts — a logical font mapped onto real ones

A virtual font (.vf) is a layer that maps the single logical font TeX sees onto actual glyphs and low-level typesetting operations. In the words of the TeX FAQ, virtual fonts are “a means of collecting bits and pieces together to make the glyphs of a font,” where the pieces are drawn from other fonts, rules, and typesetting commands with positioning information. This lets you remap the order of characters, combine several fonts into one, fake small caps, or bundle the pieces of a math font into a single typeface.

The mechanism splits the work in two. TeX itself needs only the dimensions — width, height, depth — which it reads from the companion **.tfm (TeX Font Metric)**. How each glyph is *actually drawn* — which glyph of which real font, shifted by how much — lives in the **.vf, and it is the DVI driver that reads it (dvips, dvipdfmx). So a virtual font is always a pair: a .tfm plus a .vf**. TeX positions everything from the .tfm; the driver expands the .vf and pours the result into real fonts.

Since the binary .vf is not meant for humans, there is a **human-readable text form, the .vpl (Virtual Property List)**. Written as a nested “property list,” it is convenient for specifying and inspecting a font’s details by hand. Two programs convert between the forms, and both ship with every TeX distribution (vptovf and vftovp, from the fontware tools):

  • vptovf** — .vpl (text) → .vf + .tfm (binary). Bakes a hand-written or hand-edited virtual-font description into the form TeX and the driver can use.
  • vftovp** — .vf + .tfm (binary) → .vpl (text). Turns an existing virtual font back into human-readable form so you can inspect or edit its contents.

The argument order is worth memorizing. vftovp takes virtual font, metric, output; vptovf takes description, virtual font, metric. Extensions may be omitted in both — .vf / .tfm / .vpl are supplied for you. To take an existing virtual font apart, for instance:

terminal
# 仮想フォントを人間可読の VPL に戻して中身を見る
# Turn a virtual font back into a readable VPL to inspect it
vftovp font.vf font.tfm font.vpl

# 編集後、VPL から .vf と .tfm を作り直す
# After editing, rebuild the .vf and .tfm from the VPL
vptovf font.vpl font.vf font.tfm

Place the resulting .tfm under .../fonts/tfm/<supplier>/ and the .vf under .../fonts/vf/<supplier>/ in the texmf tree, refresh the filename database with mktexlsr, and you can then locate them with kpsewhich font.vf. For the modern job of generating virtual fonts from PostScript fonts, it is more common to use **fontinst** than to write a .vpl by hand. In practice, a virtual font is something you read and fine-tune from such a tool’s output, rather than author from scratch.

JFM — the Japanese Font Metric

Japanese typesetting needs something a Western .tfm cannot give. Kanji and kana sit, by default, in a square (full-width) box, and the space between them is not the inter-word space of Western text — instead, gaps open or close only around punctuation (brackets and stops). The structure that carries this is the JFM (Japanese Font Metric). pTeX and upTeX use a binary JFM file much like a .tfm; LuaTeX-ja describes the same role as a Lua table.

The chief difference from a Western TFM is that a JFM groups characters into “character classes.” As the LuaTeX-ja manual specifies, every length in a JFM is a floating-point number in design-size units, anchored to zw (the full-width) and zh (the full-height, height + depth); each class then carries its own width, height, depth, and italic (italic correction). Class 0 always exists and holds the great majority of Japanese characters — those in no other class. Punctuation and the like go in separate classes, and a table of glue/kern to insert between one class and another is what produces the spacing around stops and brackets.

On the pTeX family, JAglue — the spacing inserted between two Japanese characters, and between a Japanese character and Western text — is added automatically at typeset time. The JFM fixes the gap between classes; between unclassed Japanese characters the default kanjiskip is used, and at a Japanese/Western boundary, xkanjiskip. The latter, alongside *kinsoku* (the rules barring certain characters from a line’s start or end), is central to the look of Japanese type. A LuaTeX-ja JFM file is a Lua script that makes a single call to luatexja.jfont.define_jfm{ ... }, with a skeleton like this:

latex
-- LuaTeX-ja の JFM(抜粋)。寸法はすべてデザインサイズ単位
-- A LuaTeX-ja JFM (excerpt); all lengths are in design-size units
luatexja.jfont.define_jfm {
  version = 3,
  dir = 'yoko',          -- 横組み / horizontal
  zw = 1.0, zh = 1.0,     -- 全角の幅・高さ / full-width, full-height
  [0] = {                -- 文字クラス 0:大多数の漢字・仮名 / class 0: most kanji & kana
    chars = { '漢' },
    width = 1.0, height = 0.88, depth = 0.12, italic = 0.0,
  },
  [1] = {                -- 句点など別クラス / a class for stops, etc.
    chars = { '。', '、' },
    width = 0.5, height = 0.88, depth = 0.12, italic = 0.0,
  },
}

LuaTeX-ja ships standard JFMs for different needs. jfm-ujis.lua is the standard, based on upnmlminr-h.tfm, a metric used in upTeX (most characters square); jfm-jis.lua is a counterpart to jis.tfm, widely used in pTeX (characters tend to be horizontal rectangles); jfm-min.lua corresponds to pTeX’s default min10.tfm. In a font definition you select one with jfm=, as in \jfont\F=HaranoAjiMincho-Regular:jfm=ujis. The binary JFMs of the pTeX family, meanwhile, convert to and from text with ppltotf and ptftopl — the Japanese counterparts of the Western pltotf and tftopl.

Listing what a font contains — fonttable and nfssfont

To see which glyphs a font actually carries, you print a glyph table (font table). The easy way from inside a document is the **fonttable package**, whose central command \fonttable{<font>} typesets a table of all the glyphs in the named font. The argument is the name of the font (more precisely, of its .tfm): cmr10 for Computer Modern Roman, pzdr for Zapf Dingbats, and so on.

document.tex
\documentclass{article}
\usepackage{fonttable}
\begin{document}
% フォント名(.tfm)を渡すと全字形の表が出る
% Pass a font (.tfm) name to get a table of every glyph
\fonttable{cmr10}

% NFSS の 4 属性で指定する版(エンコーディング/ファミリ/シリーズ/シェイプ)
% The NFSS-attribute version (encoding/family/series/shape)
\xfonttable{T1}{cmr}{m}{n}
\end{document}

To specify by the four NFSS attributes, use **\xfonttable{<encoding>}{<family>}{<series>}{<shape>}** (for example \xfonttable{T1}{cmr}{m}{n}). You can narrow the table’s range to 16-glyph blocks with \fontrange{<low>}{<high>}, up to a maximum of 256 glyphs. And \fonttext{<font>} typesets sample text set in the font rather than a glyph grid — handy for judging how it actually looks.

This fonttable is a package-form repackaging of the classic tools that ship with TeX, **nfssfont.tex and testfont.tex** (much of the package’s code is an edited version of nfssfont.tex, and its glyph-testing commands reimplement Knuth’s testfont.tex). The classic tools run *interactively*: you launch with tex nfssfont, type a font name (such as cmr10), use \table to print the chart, \init to switch to another font, and \bye to finish.

terminal
# 古典的な対話ツール:起動 → フォント名 → \table\bye
# The classic interactive tool: launch, name the font, \table, \bye
tex nfssfont
# Name of font to test = cmr10
# *\table
# *\bye

Relatedly, to log the identity of the current font, **\showfont** displays its five NFSS attributes — encoding, family, series, shape, and size. To trace font-loading behaviour itself, the tracefnt package is useful. Finally, to learn what is installed on your system and where files are read from, the starting points are **updmap, which manages the font maps, and kpsewhich**, which finds a file’s actual location (e.g. kpsewhich cmr10.tfm).