大多数作者从不会手动接触 .vf 文件。但一旦开始制作字体或把字体接入 TeX,就会需要三类强力工具:把逻辑字体桥接到实际字体上的虚拟字体,记录 CJK 字形宽度和标点间距的 JFM (Japanese Font Metric),以及显示字体实际包含哪些字形的字形表工具。本页介绍这些面向字体开发者和高级用户的低层实用工具。
虚拟字体 — 把逻辑字体映射到实际字体
虚拟字体(virtual font,.vf)是一层映射:它把 TeX 看到的一个逻辑字体映射到实际字形和低层排版操作上。借用 TeX FAQ 的说法,虚拟字体是“把零碎片段收集起来组成字体字形的手段”,这些片段可以来自其他字体、规则线以及带位置信息的排版命令。借助它,可以重映射字符顺序、把多个字体合并成一个、模拟小型大写,或把数学字体的部件组合成一个字体。
这个机制把工作分成两部分。TeX 本身只需要知道尺寸:宽度、高度和深度,这些从配套的 .tfm (TeX Font Metric) 读取。每个字形“实际怎样绘制”——使用哪个实际字体中的哪个字形、偏移多少——写在 .vf 中,并由 DVI 驱动读取(dvips、dvipdfmx)。因此虚拟字体总是成对出现:一个 .tfm 加一个 .vf。TeX 根据 .tfm 决定排版位置;驱动展开 .vf 并把结果送入实际字体。
二进制 .vf 并不是给人读写的,因此有一个配套的人类可读文本形式 .vpl (Virtual Property List)。它以嵌套的“属性列表”书写,适合手动描述和检查字体细节。下面两个程序在两种形式之间转换,所有 TeX 发行版都包含它们(来自 fontware 工具的 vptovf 和 vftovp):
vptovf—.vpl(文本)→.vf+.tfm(二进制)。把手写或手工编辑的虚拟字体描述烘焙成 TeX 和驱动可使用的形式。vftovp—.vf+.tfm(二进制)→.vpl(文本)。把现有虚拟字体转回人类可读形式,便于检查或编辑其内容。
参数顺序值得记住。vftovp 的顺序是虚拟字体、度量、输出;vptovf 的顺序是描述、虚拟字体、度量。两者都可以省略扩展名,程序会补上 .vf / .tfm / .vpl。例如拆解一个现有虚拟字体时,可以这样做:
# 仮想フォントを人間可読の 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把生成的 .tfm 放到 texmf 树中的 .../fonts/tfm/<supplier>/,把 .vf 放到 .../fonts/vf/<supplier>/,再用 mktexlsr 刷新文件名数据库,就可以用 kpsewhich font.vf 找到它们。现代从 PostScript 字体生成虚拟字体的工作中,通常使用 fontinst,而不是手写 .vpl。实践中,与其从零编写虚拟字体,不如把它看作需要阅读并微调这类工具输出的对象。
JFM — Japanese Font Metric
日文排版需要西文 .tfm 无法提供的信息。汉字和假名默认位于正方形(全角)框中,字与字之间不像西文那样用词间空格隔开;间距只会在标点(括号和句读点)周围收紧或打开。承载这些信息的结构就是 JFM (Japanese Font Metric)。pTeX 和 upTeX 使用类似 .tfm 的二进制 JFM 文件;LuaTeX-ja 则用 Lua 表描述同一角色。
与西文 TFM 最大的区别在于,JFM 把字符归入“字符类(character class)”来处理。按照 LuaTeX-ja 手册的规定,JFM 中的所有尺寸都写成以设计尺寸为单位的浮点数,以 zw(全角宽度)和 zh(全角高度,即 height + depth)为基准;每个字符类都有自己的 width、height、depth 和 italic(斜体校正)。类 0 必定存在,包含不属于其他任何类的绝大多数日文字符。标点等分到其他类,并用表记录在一个类和另一个类之间插入的 glue/kern;这就是生成字间和标点周围空白的机制。
在 pTeX 系列中,JAglue(插入在两个日文字符之间、以及日文字符与西文文本之间的间距)会在排版时自动加入。类间间距由 JFM 决定;未指定类的日文字符之间使用默认 kanjiskip,日文/西文边界使用 xkanjiskip。后者与 *kinsoku*(禁止某些字符出现在行首或行末的规则)一起,是支撑日文排版外观的核心。LuaTeX-ja 的 JFM 文件是一个 Lua 脚本,开头只调用一次 luatexja.jfont.define_jfm{ ... },骨架如下:
-- 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 随附面向不同用途的标准 JFM。jfm-ujis.lua 是标准 JFM,基于 upTeX 使用的度量 upnmlminr-h.tfm(大多数字符为正方形);jfm-jis.lua 对应 pTeX 中广泛使用的 jis.tfm(字符往往是横向长方形);jfm-min.lua 对应 pTeX 默认的 min10.tfm。在字体定义中,用 jfm= 选择,例如 \jfont\F=HaranoAjiMincho-Regular:jfm=ujis。另一方面,pTeX 系列的二进制 JFM 可用 ppltotf 和 ptftopl 与文本相互转换;它们相当于处理西文 pl/tfm 的 pltotf 和 tftopl 的日文版。
列出字体包含的内容 — fonttable 和 nfssfont
要确认一个字体实际包含哪些字形,可以输出字形表(字体表)。在文档中最方便的方法是使用 fonttable 软件包,其核心命令 \fonttable{<font>} 会把指定字体中的所有字形排成表。参数是字体(更准确地说是其 .tfm)的名称:Computer Modern Roman 用 cmr10,Zapf Dingbats 用 pzdr,依此类推。
\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}如果要按 NFSS 的四个属性指定,请使用 \xfonttable{<encoding>}{<family>}{<series>}{<shape>}(例如 \xfonttable{T1}{cmr}{m}{n})。表的字符范围可用 \fontrange{<low>}{<high>} 缩小到 16 个字形为一组的区块,最多列出 256 个字形。\fonttext{<font>} 则会排出用该字体设置的示例文本,而不是字形网格,适合判断实际观感。
这个 fonttable 是对 TeX 随附经典工具 nfssfont.tex 和 testfont.tex 的软件包化重新封装(该软件包的大部分代码是 nfssfont.tex 的修改版,其字形测试命令重新实现了 Knuth 的 testfont.tex)。经典工具的特点是*交互式*运行:例如用 tex nfssfont 启动,输入字体名(如 cmr10),用 \table 输出图表,用 \init 切换到另一个字体,用 \bye 结束。
# 古典的な対話ツール:起動 → フォント名 → \table → \bye
# The classic interactive tool: launch, name the font, \table, \bye
tex nfssfont
# Name of font to test = cmr10
# *\table
# *\bye相关地,要把当前字体的身份写入日志,可以使用 \showfont(显示当前字体的五个 NFSS 属性:encoding、family、series、shape 和 size)。如果想追踪字体加载行为本身,tracefnt 软件包很有用。最后,要了解系统安装了什么、文件从哪里读取,起点是管理字体映射的 updmap,以及查找文件实际位置的 kpsewhich(例如 kpsewhich cmr10.tfm)。