2. glyph轮廓线(outline)
2.1 像素,点及设备分辨率
在编写计算机图形程序时,一个很通常的假设是不同的物理设备(显示器或打印机)对像素的度量方式是不一样的。通常来说,像显示器或打印机这些输出设备在水平或垂直方向上往往有多种分辨率,这一点是被文字渲染高度重视的。
我们通常使用两个以dpi为单位的数字来定义设备的分辨率,如分辨率为300*600dpi的打印机在水平方向上有300个像素(译注1),在垂直方向有600个。电脑显示器的分辨率视尺寸不同而不同(同样是640*480,15寸和17寸的像素大小不同),当然也和显卡所处的模式有关(译注 2)。
因为像素的实际尺寸决定于具体设备,所以文本的大小通常使用设备无关的单位——磅(points)来表示。在印刷领域,点是一个物理单元,一个点等于1/72英寸。如,大多数Roman书籍使用10pt和14pt来印刷正文。
磅与像素之间的关系可以通过下面的公式计算,
pixel_size = point_size * 分辨率 / 72
分辨率的单位是dpi。由于水平和垂直分辨率可能是不同的,a single point size usually defines a different text width and height in pixels。
和我们通常所想像的不太一样的是,一串文字在打印或者显示时所占据的实际像素个数并不是直接取决于字符的实际尺寸。两者之间的关系有点复杂,而且可能与字体设计师的一些设计取舍有关。这些在下一章节详细描述(参见关于EM方块的描述)。
2. glyph的矢量表示
在字体文件中,轮廓线由一组称为contours的封闭线条组成。每个contour把glyph划分成了内、外两个区域,每个contour可由直线或贝塞尔曲线构成。
曲线可以是二次(conic贝塞尔)或三次(cubic贝塞尔)多项式,通过控制点(control points)来定义,这取决于字体的格式。注意,conic贝塞尔曲线在文献中常称作二次(quadratic)贝塞尔曲线。轮廓上的每个点都有一个标志位用于表示它是一个控制点还是普通点。对这些点进行缩放就会导致整个曲线的缩放。
glyph轮廓线被假想在一个的网格中(坐标单位是unit)。轮廓线的点的坐标在字体文件中通常以16bit整数来存储,网格的中心坐标是(0,0),整个网格的范围是-16384至16383(虽然在某些格式中点坐标可以是浮点数,如Type 1,但出于简单,我们仅分析整数的情况)。
网格和传统的二维坐标系的坐标轴方向是一致的, X轴从左至右,Y轴从底至上。
在创建glyph轮廓线时,字体设计者假想它们在一个正方形——EM方块之中。典型地,可以把EM方块理解为一块绘制字符的平板(译注:EM也位于网格之中)。而EM方块的尺寸(译注:在网格中所占据的unit个数)是一个非常重要的指标,原因是:
a. 它是轮廓缩放时的参考。比如,字符大小为12pt,在300*300dpi的设备下对应着12*300/72=50个像素。这个50就是EM方块在输出设备上的大小,换句话说,缩放网格的units(译注3)与缩放实际像素有着如下的对应关系:
pixel_size = point_size * resolution / 72
pixel_coord = grid_coord * pixel_size / EM_size
b. EM方块的尺寸越大,字体可以支持的分辨率就越高。举个极端的例子,EM大小为4个units,那整个EM方块中只有25个位置可供点来放置,这显然是不够的。典型情况下,TrueType字体的EM方块大小为2048units,Type 1 PostScript字体是1000units,但点坐标可以浮点形式表述。
注意,只要字体设计者愿意,glyph完全可以超出EM方块的范围。EM方块给设计者以便利,这是传统印刷留给我们的宝贵财富。
网格中的units常被称为font units(funit)或EM units。
前面已经说过,使用之前的公式计算出来的pixel_size并不能代表字体在屏幕上的实际大小。其实它表示的是被显示字符的EM方块大小。字体设计者可以把glyph任意地放置在EM方块中(译注:可以不充满整个EM)。这也就解释了为什么下图中的文字虽然字号相同但高度却各不相同的。
你可以看到,虽然都是16pt,但Courier系列字体的高度比Arial小一点,而比Times New Roman要小不少。这一切都取决于字体设计者。
3. hinting及位图渲染
存储于字体文件中的轮廓线也称为“主”轮廓线(译注4),轮廓线各点的坐标以font units来表示。在它被转换成位图之前,先必须缩放到指定的大小/分辨率。这是个简单的数学变换过程,但是总会产生一些不想要的副作用,如字母E和H的竖线高度或宽度不一致。
所以,要正确地渲染glyph则要求缩放后的点对齐到目标设备的像素网格上,这个操作称之为grid-fitting(通常也叫hinting)。这个过程最主要的目的是保证一些关键线条的宽度和高度在整个字体中是一致的(比如一般要求I和T中间竖线的宽度相同),以及控制类似stem和overshoot(译注5)这样的属性,它们在尺寸较小时往往会有问题。
大多数矢量字体的glyph都附带有一些控制数据和程序。有多种方式可以达到grid-fitting的效果,以下概述了几种方法,
a. 显示grid-fitting
TrueType字体定义了一个基于指令栈的虚拟机,每个控制程序可以编写超过200条指令(大多数都是和几何操作相关)。每个glyph由轮廓线和控制程序组成,控制程序负责开展由字体设计者预先定义好的grid-fitting操作。
b. 隐式grid-fitting(亦称hinting)
相比上面,Type 1字体的方法要简单得多。每个glyph由轮廓线及一些hint组成,hint描述字体重要特征,如stem,宽度均匀等。hint的种类并不多,而且是由最终的渲染程序来解释这些hint以形成最终的轮廓线。
c. 自动grid-fitting
某些字体的轮廓线不含有任何控制信息,除了某些字体度量信息外,如advance width和height。如此就需要渲染程序通过“猜测”来完成grid-fitting。
下表总结了各种方法的利弊,
grid-fitting 机制 | 优点 | 缺点 |
显示 | 质量. 小尺寸下效果很好,适合屏幕显示。 一致性. 不同的渲染程序得到的渲染结果相同。 |
速度. 如果控制程序较复杂,则执行速度较慢。 体积. 控制程序可能会很长。 技术难度. 要写好控制程序很难,相关工具较少。 |
隐式 | 体积. 比显式hint占据的存储体积小。 速度. 通常较快。 |
质量. 小尺寸下常有问题,开启反锯齿会好一点。 不一致性. 最终渲染结果取决于渲染程序,即便是同一渲染引擎的不同版本最终效果也有可能千差万别。 |
自动 | 体积. 没有控制信息,文件体积最小。 速度. 取决于自动hinting的算法,通常比显示hinting要快 |
质量. 尺寸下常有问题,开启反锯齿会好一点. 速度. 取决于算法 不一致性. 最终渲染结果取决于渲染程序,即便是同一渲染引擎的不同版本最终效果也有可能千差万别。 |
----------------------------------------
译注1:关于dpi,一般认为是dot per inch,是印刷领域的常用度量单位,而另一个概念ppi,则是pixel per inch,常用于说明显示器等设备的分辨率。文本没有明显去区分这两个概念,但在某些文章里是严格区分这两者的,因为在某些设备,一个pixel包含 RGB三个物理dot。
译注2:原文The resolution of a typical computer monitor varies with its size (15" and 17" monitors don't have the same pixel sizes at 640x480), and of course the graphics mode resolution.
译注3: EM所拥有的units个数是不会随着缩放倍数而增加的,EM的缩放导致unit变大或变小。可参考下图:
译注4: 我的理解是,相对于hinting的微调来说,字体的整体外观还是决定于轮廓线。
译注5:什么是overshoot? In typeface design, overshoot refers to the degree to which a round or pointed letter's (like O or A) highest and lowest points exceed those of a comparably sized "flat" letter (like X or H), to achieve an optical effect of being the same size.
(转载请注明出处)