1. 概述

1. PostScript / Type 1
PostScript是一种页面描述语言,用于列印图像和文字。它既像程序代码一样具有可读性,又能表示出可任意放大和缩小的矢量图。
Adobe公司于1985推出PostScript,用于解决当时不同打印设备接口不兼容的问题。PostScript 独立于设备。也就是说,PostScript文件可以在任何PostScript设备中运作。同样的影像,可在一般的雷射印表机上得到300dpi的打印效果,也可以在图像艺术设备供应商Linotype的imagesetter中得到漂亮、清晰的2400dpi效果。用户不需要受限于特定的某个生产商,可自由选择适合自己要求的设备。
在PostScript的发展进程中,Apple公司有重要的推动作用。Steve Jobs向Adobe投资了250万,让Adobe为Apple LaserWriter编写PostScript控制器,使它输出「typesetter」的高品质。在桌上型电脑风行的背景下,它们的结合挽救了Apple,也让Adobe变成了有钱的公司,很快地PostScript就成了印前业的国际性混合语。
PostScript字体,是按 PostScript 页面描述语言 (PDL) 规则定义的字体。PostScript字体也被称为Type 1字体。
从用户的角度上看,没必要认为PostScript是老掉牙,不值得学习的东西。学这个东西,大概有几个用途:
- 修心养性,打发时间,PostScript是可以当作Logo语言来玩的
- 作为一种图形学学习的工具
- 作为一种排版后端,也就是说,你可以实现一个类似TeX的排版软件,用这个作为中间或者最终的呈现形式
但是,为什么有很多人对PostScript有老掉牙的概念呢?主要是PostScript解释器少,教程少。当然还有一个重要的原因是,PostScript这东西,虽然打印机里面用,印刷机里用,但是在我国其实没怎么取得特别大的商业上的成功。据信,Apple当年发售LaserWriter打印机的时候,Adobe是能从一台打印机中获取1000美元的(约现在的2400美元强)。除了Adobe的商业解释器外,还有一些解释器:
- GoScript,DOS/Windows用解释器,这个是商业版,由LaserGo Inc.开发,开发者是个越南裔Truc D. Nguyen。不过官网在2002年之后就打不开了
- Ralpage,Level 2解释器,发布在Xorg的R5里面,由Crispin Goswell开发,在现在的大部分机器上实际上是编译不过去的(其源码还有一定的教学意义)
- GhostScript,Level 3解释器,这个是我们最开始使用的解释器,也是开源时间最久的解释器,构成了开源软件的基础部件之一。本文以及之后的文章都会在这个解释器上操作
- xpost,一个用C实现的Level 3解释器。但是实现不完全,项目地址:https://github.com/luser-dr00g/xpost
中文资料里面,有说GhostScript是GoScript销量不好后卖掉后的修改版,这大概是谣传。如上文描述,GoScript的生存周期最后到了2002年。GhostScript的第一个版本是1988年8月发布的。而GoScript的商标是在1989年注册的,申请时间是1988年的11月。对一对这些时间点就知道不太可能。
这些背景知识讲完了,接下来该讲一些编程语言上的知识了。
PostScript语言受Forth语言影响,使用stack作为数据存放的结构,那么在语言上就呈现出了逆波兰式的形式,也就是说,2 + 3可以表示为:
2 3 add
我们在上面的gs解释器中可以输入:
2 3 add ==
结果即:
GS>2 3 add ==
5
我们稍微搞一个复杂的例子,求坐标(x, y)到坐标原点的距离,比如说这个点是(10, 20),那么求值可以这样:
10 20 dup mul exch dup mul add sqrt
结果即:
GS>10 20 dup mul exch dup mul add sqrt ==
22.3606796
逆波兰式(Reverse Polish Notation),是波兰式(Polish Notation)的变体。这个表记是波兰逻辑学Jan Łukasiewicz在1924年发明出来的。这东西的定义很简单,也很实用。实用的地方,就是不用括号。比如(a+b)*c的表示:
* + a b c
用逆波兰式表示:
a b + c *
这东西枯燥难记不?倒也不是,如果学过一点日语,大概知道日语跟这玩意还是有一点相似的,比如,我们拿wikipeadia上的例子:
私が 箱を 開けます。
这句子大意是“我打开了箱子”,要是拿逆波兰式写(日语词换成英文词),就是这样:
I box open
话题再回到Forth上来。Forth这东西,也是可以直接用硬件解码的,也就是Forth CPU。如果我们搜过一些PostScript打印机的商品的话,大概会发现一些信用卡卡片大小的电路板,这类东西上,大概就有个类似Forth CPU的专门用于PostScript解码的解释器。
其中,逆波兰表达式,英文为 Reverse Polish notation,跟波兰表达式(Polish notation)相对应。之所以叫波兰表达式和逆波兰表达式,是为了纪念波兰的数理科学家 Jan Łukasiewicz。其在著作中提到:
我在1924年突然有了一个无需括号的表达方法,我在文章第一次使用了这种表示法。
- 平时我们习惯将表达式写成 (1 + 2) * (3 + 4),加减乘除等运算符写在中间,因此称呼为中缀表达式。
- 而波兰表达式的写法为 (* (+ 1 2) (+ 3 4)),将运算符写在前面,因而也称为前缀表达式。
- 逆波兰表达式的写法为 ((1 2 +) (3 4 +) *),将运算符写在后面,因而也称为后缀表达式。
波兰表达式和逆波兰表达式有个好处,就算将圆括号去掉也没有歧义。上述的波兰表达式去掉圆括号,变为 * + 1 2 + 3 4。逆波兰表达式去掉圆括号,变成 1 2 + 3 4 + * 也是无歧义并可以计算的。事实上我们通常说的波兰表达式和逆波兰表达式就是去掉圆括号的。而中缀表达式,假如去掉圆括号,将 (1 + 2) * (3 + 4) 写成 1 + 2 * 3 + 4,就改变原来意思了。
现实中,波兰表达式和逆波兰表达式,具体用于什么地方呢?
波兰表达式(前缀表达式),实际是抽象语法树的表示方式,比如中缀 (1 + 2) * (3 + 4) 编译时转成的抽象语法树为
*
/ \
+ +
/ \ / \
1 2 3 4
这个操作符就是根节点,操作数为左右子节点。我们将这棵树用符号表达出来,可以写成 (* (+ 1 2) (+ 3 4))。这实际就是 Lisp 的 S-表达式。S-表达式可看成将整棵抽象语法树都写出来,每层节点都加上圆括号。
至于逆波兰表示式,可用栈进行计算,天生适合于基于栈的语言。遇到数字就将数字压栈,遇到操作符,就将栈顶的两个元素取出计算,将计算结果再压入栈。比较典型的基于栈的语言为 Forth 和 PostScript。
2. TrueType
Apple LaserWriter基于PostScript,但PostScript字体是加密过的,Adobe通过发售认证得到可观的收入,所以他们不想向苹果免费转让这个软件。
之后微软加入,把TrueType加入Windows3.1。微软与Monotype公司合作,花大力气制作了一批高品质TrueType字体,并使其可以与当时PostScript设备捆绑的核心字体兼容,比如Times New Roman体(与Times Roman兼容)、Arial体(与Helvetica体兼容)和Courier New体(与Courier体兼容)。
Windows系统的字体格式基本统一成TrueType。Apple的Mac OS上,PostScript和TrueType鼎力对抗。后来Linux上,TrueType也成为标准字体。
TrueType字体中的字符(或字形)轮廓由直线和二次贝塞尔曲线(bézier)片段构成。在数学上,比PostScript使用的三次贝塞尔曲线更容易处理。对于多数形状,三次要比二次贝塞尔曲线需要更多的点来描述。同时这个差异意味着,不能将Type 1无损地转换为TrueType格式,但是可以无损地将TrueType转换为Type 1。
TrueType Reference Manual
https://developer.apple.com/fonts/TrueType-Reference-Manual/
3. OpenType / Type 2
1995年,微软联合Adobe开发了OpenType,可以把PostScript字体嵌入到TrueType的软件中,支持Mac OS、Windows、Linux等多个平台。OpenType是Type 1和TrueType的超集,于是OpenType也叫Type 2字体。
OpenType已经成为业内标准。包括Adobe、微软、Apple在内,越来越多的软件厂商支持OpenType字体格式,越来越多的字体厂商将自己的字库升级到OpenType。
OpenType定义了OpenType文件名称的后缀名。
- 包含TrueType字体的OpenType文件,后缀名为.ttf,
- 包含PostScript字体的文件,后缀名为.OTF,
- 如果是包含一系列TrueType字体的字体包文件,那么后缀名为.TTC。
在软件中选择字体时,字体名前的图标指出,这个字体是OpenType格式还是TrueType格式。

OpenType? specification
https://docs.microsoft.com/zh-cn/typography/opentype/spec/
4. 中文TrueType字体
旅美学者房骞骞(FangQ)于2004年10月创建文泉驿项目,致力于开源汉字字体的开发。它提供了很好的TrueType中文支持,发布了第一个覆盖GBK字符集的开源矢量字库,已经逐渐成为主流Linux发行版的首选中文字体。