字体常见问题解答
在我们深入细节之前,我们想解释一下为什么字体是一个难题。Graphviz(和其他程序)中文本字体的命名和渲染非常复杂。有几个原因
- Graphviz 在各种系统上运行:Linux 和其他类 Unix 系统、Microsoft Windows 和 Mac。
- Graphviz 拥有各种各样的输出格式:面向光栅的格式,如 PNG 和 GIF;基于路径的格式,如 Postscript、PDF 和 SVG;一些特殊的旧格式,如 troff PIC。
- 通常,输出将被下载并在与创建布局的计算机或其他设备不同的计算机或其他设备上显示。
- Graphviz 布局的大小和外观应保持一致,无论输出格式如何。
- Graphviz 可以运行外部库,这些库可以帮助命名和渲染文本字体,但它们不是必需的,简化的 Graphviz 工具可以在没有这些库的情况下构建。事实上,Graphviz 甚至可能必须在没有安装字体文件的系统上运行。
- 有几种主要的字体文件格式需要支持。
- 应支持非西方、国际字符集。
- Graphviz 应提供一套标准字体。
- 应易于指定标准字体。
- 用户应能够加载自己的自定义字体。
- 输出应尽可能小以加快下载速度。
- 输出应允许在给定格式下获得最佳渲染效果。
- 输出文件应易于后期处理,例如,如果可能,保留原始图形的对象。
- 解决支持库和流行外部工具中已知错误或缺少功能非常有用。
这是一个很高的要求。一些目标相互冲突。通常,我们的方法是定义有利于便利性和美观输出的默认值,并为用户提供覆盖默认值的选项。
概述
在下文中,我们将假设 Graphviz 的“标准”版本,它包含所有支持库(fontconfig、gd、Cairo 和 Pango),在具有标准字体文件安装的台式机系统或服务器上运行。
graphviz 布局引擎(dot、neato 等)创建布局,节点的大小根据包围文本标签的大小确定。这需要知道文本块的大小,而这又需要知道字体字形的度量以及它们在单词中的组合,考虑到单词间距、字距调整、提示等。因此,整个过程是:字体规范,然后是文本布局,最后是 Graphviz 输出(以及目标显示器或设备上的最终渲染,这可能由 Graphviz 工具执行,也可能不执行)。
通常,字体通过族名(fontname
)和其他属性(见下文:“字体选择”)来选择。然后,fontconfig 将请求与系统字体匹配。
注意:在较早版本的 Graphviz 中,fontname
只是一个文件名。这要求精确的文件名匹配(在幕后,有一些帮助性的名称转换,例如,将 Times-Roman
转换为 Times
,或在 Windows 系统上将 Helvetica
转换为 Arial
(当然,我们知道它们之间有区别)。在 fontconfig 下,fontnames 是族名,fontconfig 将它们与找到的最近字体匹配。这总是“成功”,但不幸的是,如果 fontconfig 对“接近”的理解与你的不一致,就会产生出乎意料的结果。当您指定自定义(或不存在)字体时,例如,Steve-North-Handwriting
,fontconfig 会静默地回退到安全字体,例如打字机字体。
文本布局由 pango 执行,它接受文本并计算具有确定节点大小的度量的布局。
尽管对于许多输出格式(以及将来可能更多的格式),线绘制由 cairo 提供,但对于光栅输出格式,字体渲染会通过 cairo 传递给 freetype。如果 gd 用于绘制,则也会调用 Freetype。(当 Graphviz 在没有 cairo 的情况下构建时,gd 可以被显式请求,例如 dot -Tpng:gd
,或者默认请求)。Freetype 提供抗锯齿、提示、字距调整和其他低级字体功能。
字体度量是从运行 Graphviz 的系统上安装的字体中获取的。当 Graphviz 输出光栅格式时,结果得到保证,因为 freetype 会立即将字体渲染成像素。另一方面,对于基于路径的格式,例如 Postscript (-Tps
) 和 SVG (-Tsvg
),最终渲染可能在完全不同的平台上完成,并且安装了不同的字体文件。显然,您的里程可能会有所不同。在 Postscript 的情况下,Graphviz 中的驱动程序将文本块的预期度量传递给渲染器,并要求它进行最终拉伸(或压缩)以强制文本适合布局时有效的度量。在 Graphviz SVG 中,只有希望和祈祷 SVG 渲染程序的字体与 Graphviz 运行时 fontconfig 和 freetype 使用的字体匹配。(稍后将详细介绍。)
默认字体和 PostScript 字体
graphviz 中的默认字体一直是 Times-Roman
。
Graphviz 在历史上支持一些“标准”Postscript 字体,最初是 Times-Roman
、Helvetica
、Courier
和 Symbol
。此列表后来由 Adobe 扩大到包括 35 种字体,它们是
AvantGarde-Book AvantGarde-BookOblique AvantGarde-Demi
AvantGarde-DemiOblique Bookman-Demi Bookman-DemiItalic
Bookman-Light Bookman-LightItalic Courier Courier-Bold
Courier-BoldOblique Courier-Oblique Helvetica
Helvetica-Bold Helvetica-BoldOblique Helvetica-Narrow
Helvetica-Narrow-Bold Helvetica-Narrow-BoldOblique
Helvetica-Narrow-Oblique Helvetica-Oblique NewCenturySchlbk-Bold
NewCenturySchlbk-BoldItalic NewCenturySchlbk-Italic
NewCenturySchlbk-Roman Palatino-Bold Palatino-BoldItalic
Palatino-Italic Palatino-Roman Symbol Times-Bold Times-BoldItalic
Times-Italic Times-Roman ZapfChancery-MediumItalic ZapfDingbats
不幸的是,fontconfig 不直接识别 PostScript 风格的字体名称,因此 Graphviz 将其 PostScipt 名称列表中的自定义映射映射到 fontconfig 家族名称,以便在所有基于 cairo 和 gd 的渲染器中使用。在 -Tps
输出中,这些字体在没有名称转换的情况下使用。
字体选择
.gv 图表中的 fontname 属性是 fontconfig 风格的规范。
来自:http://www.fontconfig.org/fontconfig-user.html
Fontconfig 为库可以接受和生成的模式提供文本表示。表示分为三个部分,第一部分是字体族名称列表,第二部分是点大小列表,最后是附加属性列表
<families>-<point sizes>:<name1>=<values1>:<name2>=<values2>...
列表中的值用逗号隔开。名称不需要包含字体族或点大小;它们可以省略。此外,还有一些符号常量同时指示名称和值。以下是一些示例
名称 含义 Times-12
12 点 Times Roman Times-12:bold
12 点 Times Bold Courier:italic
默认大小的 Courier 斜体 Monospace:matrix=1 .1 0 1
用户首选的等宽字体,具有人工倾斜
Graphviz 目前有一个单独的属性用于指定字体大小。
TODO:我们应该允许 fontconfig 风格的规范。Times-20
目前不会导致 20pt 字体。这可能是因为对 Postscript 字体名称的 -
的特殊处理。
TODO:在字体名称中使用 :
时,我们似乎存在一个错误,这可能是因为对 Windows 中的文件名的特殊处理。在字体名称中,使用 <space>
而不是 :
来分隔值。-Nfontname="Courier:italic"
不会在 graphviz-2.16.1 中生成斜体字体,但是:-Nfontname="Courier italic"
会起作用,但 -Nfontname="Monospace matrix=1 .1 0 1"
不会。
使用 fontconfig 管理字体
如何查看可用的字体?
$ fc-list
如何查看 dot 使用的字体?
$ dot foo.gv -Tpng -o foo.png -v 2>&1 | grep font
如何添加自定义字体?
在当前版本的 Graphviz 中,使用 fontconfig、Cairo 和 Pango,这不能仅仅通过将文件放在当前目录中或设置 DOTFONTPATH 环境变量来完成。您的自定义字体必须由 fontconfig 工具显式安装。
对于单个字体,例如 foo.ttf
$ mkdir -p ~/.fonts
$ cp foo.ttf ~/.fonts/
可以运行 fc-cache
来加快使用 fontconfig 的速度。
$ fc-cache
对于 Windows 用户,可以转到 C:\windows\fonts
文件夹,并使用下拉菜单中的“文件”->“安装新字体”来安装字体。
对于新的字体目录,例如 /Library/Fonts
,添加一个新的 <dir>
元素
<dir>/Library/Fonts</dir>
到 .conf
文件中。请注意,该文件必须具有由 fontconfig fonts.dtd
指定的正确 xml 结构。.conf
文件的可能选择是与系统范围的 fonts.conf
文件位于同一目录中的 local.conf,或您主目录中的 .fonts.conf
。
如何……字体?
参见:http://www.fontconfig.org/fontconfig-user.html
我可以通过文件名而不是族名来指定字体吗?
对不起,答案是否定的。(原因是,为了使此方法起作用,Graphviz 必须在调用 fontconfig 之前拦截字体查找,而当 Pango 正在查找字体时,这无法完成。)
一些版本的 fontconfig 似乎识别路径名并尝试使用它,但这并非总是如此。
如何确保选择了特定字体?
在 fontname 中提供足够的规范,并使用 fc-match
测试它以确保选择了您所需的字体。(请注意,这不能保证在 -Tps
或 -Tsvg
渲染中使用相同的字体,在这些渲染中,我们依赖最终打印机或计算机上的可用字体。)
请注意,如前所述,缺点是 Graphviz 在 fontconfig 未找到非常好的匹配时,无法发出太多警告,因为 fontconfig 会愉快地回退到某些标准字体。如果 fontconfig 开发人员可以在其 API 中提供一个反映字体匹配质量的指标,那将非常棒。
SVG 字体呢?
Graphviz 拥有一个我们编写的原生 SVG 驱动程序(它是默认驱动程序),以及 Cairo 的 SVG 驱动程序(使用 -Tsvg:cairo
获取)。
Graphviz 的原生 SVG 驱动程序默认情况下会生成 Windows 兼容的名称,例如 Times New Roman
或 Arial
。这些名称在很多情况下都有效(例如在 Windows 上运行的 Firefox),但不能保证可移植性。如果设置 -Gfontnames=ps
,则会获得 Postscript 名称,例如 Times-Roman
。如果设置 -Gfontnames=svg
,则可以保证获得符合标准的 SVG。SVG 标准规定,合法的通用字体名称是 Serif
、Sans-Serif
和 Monospace
(以及 Cursive
和 Fantasy
,我们在 Graphviz 中未使用)。我们生成这些名称。坏消息是,各种下游渲染器和编辑器可能以不同的方式解析通用字体名称,因此尚不清楚您的 SVG 将是什么样子。许多 W3C 示例展示了如何使用 CSS(层叠样式表)通过按查找优先级顺序提供字体族名称列表来解决此问题,但某些下游处理器(如 Linux 中的 inkscape 编辑器)没有实现 CSS,因此我们在这方面存在问题。
Cairo SVG 驱动程序以一种有效但笨拙的方式解决了这个问题:它只是将所需的字体编码为目标 SVG 中的直线和曲线。对于小型示例,-Tsvg:cairo
大致比 -Tsvg
大 10 倍,但为了正确性,也许值得这样做。另一个问题是,此类 SVG 渲染速度要慢得多,毫无疑问,这是因为它绕过了任何系统字体渲染服务,并以传统的方式进行渲染。
Postscript 字体呢?
TODO:在这里说些什么。非 ASCII 字符(如 Latin1
)怎么样?如何像过去使用奇怪的轮廓字体示例那样通过 -L
加载自己的字体。
非标准 Graphviz 构建的“如果”问题
以下内容仅适用于您通过配置和编译源代码来构建自己的 Graphviz 版本以构建自己的自定义可执行文件的情况。如果您不知道这是什么意思,那肯定不包括您。
没有 freetype
当在没有 freetype 的系统上构建 graphviz 时,只有 gd 渲染器可用于位图输出,并且唯一可用的字体是一组小的内置位图字体。这些字体的质量很差,而且 dot ... -v 2>&1 | grep font
会显示字体是 <internal>
。这实际上可能适合在服务器上安装最小的 graphviz 程序,因为服务器上可能根本没有安装字体。
没有 fontconfig
如果在没有 fontconfig 的系统上构建 graphviz(例如 Redhat-7),则 fontname 属性将被解释为字体文件名。系统目录将被搜索以查找此文件,或者目录可以使用 GDFONTPATH
环境变量(或出于历史原因的 DOTFONTPATH
)指定。Graphviz 将使用 gd 和 freetype 来获取度量和渲染文本。没有 fontconfig 支持,将无法使用 pango/cairo 渲染器。
禁用 fontconfig
Pango/cairo 依赖于 fontconfig,因此要禁用 fontconfig,您还需要禁用 pango/cairo。最简单的方法是暂时编辑 /usr/lib/graphviz/config
并删除整个 libpango
块。
请注意,对该文件的任何更改将在下次更新 graphviz 或使用安装程序权限运行 dot -c
时丢失。
禁用 pango 后,graphviz 将使用 gd,即使它是在有 fontconfig 支持的情况下构建的,它仍然允许将字体名称作为文件名给出。
您也可以在构建时使用配置脚本选项禁用 cairopango。
没有 gd
Cairopango 在没有 gd 的情况下工作。我们将 graphviz 迁移到 pango/cairo 库,但 gd 仍然提供一些难以替换的功能,例如 JPEG、GIF 和调色板颜色位图输出。但是,只要 pango、cairo、fontconfig、freetype 可用,字体支持就可以完全正常工作,而无需 gd。
没有 pango/cairo
没有 pango/cairo,一些关键渲染器只能与 gd 一起使用,gd 会产生质量较低(但更小)的输出。
展望未来,我们预计将更多地依赖 pango 来完成以下工作:换行、每个标签中的多个字体、双向文本和其他国际化功能。
没有 gd 也没有 cairopango
这基本上是原始的 Graphviz,没有任何外部字体。它无法渲染任何光栅格式,因此主要适用于 Postscript。它依赖于一些内部字体表