Yuanji's Blog

这个博客已通过认证

自由研究 1: 字体料理

📅 ( 更新 ) | 🏷️ ,

上回说了如何使用 fontconfig 搭配字体,咋看之下似乎很科学。但有一个明显的问题,就是如果某个软件、或者某个系统压根不支持 fontconfig 呢?没有错,所有在 fontconfig 里做的努力都打了水漂。为了解决这个问题,或者兼顾不同的平台,很多字体爱好者想到了一个办法,那就是把自己喜欢的或者想要的几个字体合到一块不就可以了?确实是这样,今天就简单地说一下怎么修改字体,因为修改的过程很像做菜,标题就取作「字体料理」了。

首先说一下为什么会需要修改字体,大体上我觉得有两类:

  1. 可能完全是个人喜好问题,比如你喜欢一款字体里的阿拉伯数字,但是不喜欢这款字体里的西文字母,或者非常中意一款中文字体,但是嫌弃和它搭配的其他西文字母。这个时候一些人就想到了取长补短的方法,把一款字体作为基础字体,剔除里面自己不喜欢的字形,再从别的字体里借一些自己中意的字形过来。
  2. 处于可读性的考虑,中文可能这个情况不明显。但是西文字母和一些日文字符就会有这个问题了。比如说数字「1」和字母「l」以及大写字母「I」,还有数字「0」和字母「O」的区别,比如说日文里的片假名「カ」和汉字的「力」,比如字号小的时候不太分得清「つ」和「っ」,甚至有的时候分不清浊点半浊点。到底哪个是哪个?有人就通过一些小修改让这些暧昧不清的字形有自己更明显的特征。

比如说像下面两张图片里这款叫作 Migu 的字体就是爱好者合成的,主要特点是在一款叫 M Plus 的基础让文字更可读,比如把半浊点(就是假名右上角的圈圈)放大,片假名的长音符号「ー」前面稍微翘点头,数字的「一」后面翘点儿尾巴等等,另外 M Plus 里没有的字形就从 IPA 字体里引进。

Migu 1C 的可读性
Migu 1C 的可读性
Migu 1P 对暧昧字形的处理
Migu 1P 对暧昧字形的处理

有了这款字体之后,又有其他爱好者做出了一款叫作 Ricty 的字体,这个字体就更复杂了,Ricty 这五个字母前四个分别是 Inconsolata 作者的首字母 R,上面那款 Migu 字体的作者首字母 i,M+ M Type-1 作者的首字母 c,加上 IPA Gothic 字体基于的 TB Gothic 的作者首字母 t。最后加上 Ricty 的作者自己的首字母 y 就得到了这款字体的名字。与上面那款字体不一样的是,这款字体有个明显的特征,就是把西文字形交给一款专门的西文字体,余下的字体交给和文字体,然后再做其他的微调。这个做法其实在合成字体(尤其是程序员编程使用的等宽字体)上非常常见。比如受 Ricty 启发而派生的 Cica 字体,还有国内爱好者制作的 Sarasa-Gothic 基本都属于这个类型。无非是选用的西文,CJK 字体不一样(有的还会友好地加入各种符号 logo 等,像 Cica 还有自带 emoji 的版本)以及生成字体选用的手段不同而已。据我观察看到大体有两种方案,像 Cica/Ricty 使用的是 fontforge 脚本,像 Sarasa-Gothic 使用的是 otfcc。后面那种我没有仔细研究过,fontforge 我使用了下比较直观,文章最后可以简单说一下。

接下来讨论的一个问题就是合成字体的分发(distribution)问题。为什么有了 Ricty 字体之后,爱好者还要做出 Cica 字体,虽然有一部分原因是 Ricty 的西文字体 Inconsolata 字体可能有爱好者不满意(我是挺喜欢这个字体的),但有一个重要的原因就是许可证(License)的问题。一般来讲,你的字体由多款字体合成,这款新字体需要符合所有这些字体的许可证。基本上,我粗略地理解,在许可证不互相矛盾的情况下,需要遵守最严格的那个许可证。这也就是为什么 Ricty 的作者其实从来没有发布过 Ricty 这款字体(因为 Inconsolata 这款字体要求派生的字体不得再分发),他发布的只有制作这款叫作 Ricty 字体的配方,就是一组指令,你照着执行就能合成出 Ricty 的字体,但是你做了这款字体,你也和 Ricty 的作者一样,不得再次分发这款字体,也就是说你只能教别人怎么合成字体,你不能把字体放在公开的地方供人下载。这显然不太利于这款字体传播,毕竟不是所有人都有兴趣去合成字体的(和料理食物是一个道理吧:D)所以,Cica 也好 Sarasa 也好在选择字体方面可能有这样的考虑,这两款合成字体是可以再分发的,普通用户可以直接下载由作者提供的字体文件而没有法律风险。

如果看到这里的读者,甚至萌生了自己合成字体的想法,我想上面提到的一些关键字也够你展开调查了,比如说安装一下 fontforge 或者其他字体制作、修改软件感受一下。fontforge 自带有一个 Python 的绑定,你可以使用 Python 脚本来批量操作你需要的动作,比如说选择所有的西文字母,把他们换成其他字体的字形,比如说选择所有的假名对它们进行你想要的操作,这些选择,在脚本里可以通过 Unicode 的范围决定,fontforge 的软件里内置了很多常用字符的 Unicode 范围。然后对于字形的变化,fontforge 里是通过一个矩阵函数实现,这个 CSS 里有几乎相同的概念,感兴趣的朋友可以读一读这篇文章 理解 CSS3 transform 中的 Matrix(矩阵) 就知道我说的 fontforge 里的矩阵变换是什么意思了。想用 Python 合成修改字体的朋友可以看 http://dmtr.org/ff.php 这里的文档,里面主要有两部分组成 psMat 和 fontforge,前者是用来方便生成变换矩阵存在的快捷功能,后者是具体操作字体的部分,一般的手段是先打开字体,然后操作选中的 glyph,如果要更细腻的操控可以操作 glyph 对应的 layer,最后完成所有操作之后 generate 字体就行了。Cica 的脚本提供了一个比较直观的例子可以作为参考。

以下是打开 Cica 字体的时候 fontforge 的样子。

Cica 用 fontforge 打开后的一部分字形
Cica 用 fontforge 打开后的一部分字形
最新加入 Unicode 的日本新年号的合体字形
最新加入 Unicode 的日本新年号的合体字形

最后,我得说字体的知识真的非常复杂,我提两个问题抛砖引玉下:

  1. 为什么字体可以跨平台、跨机种使用?在没有 Unicode 之前,或者说不使用 Unicode 字符集的平台,字体是如何找到正确的字形的?
  2. 合字效果(Ligature)怎么做到的,比如说有的字体打出 f 和 i 两个字母,会自动合并到一块,甚至有些字体打出 ! 和 = 会自动生成一个不等于号 ≠

因为篇幅的问题我就不展开说明了,一方面我也没有深入研究,万一说错误导了读者就不好了。等我有时间了更有自信的时候再写字体的文章吧。接下来我应该会去读 CJKV Information Processing 这本书更好地了解字符集、字体相关的知识。

以上。