在作者看来,字体光栅化是计算机科学中最有趣的领域之一。如果音乐是物理学的主观应用,那么字体光栅化几乎肯定是计算机科学的主观应用。本文的目的有三个:首先,介绍可用于光栅化过程的各种方法;其次,针对桌面应用程序的需要,对这些方法进行批判性分析;最后,将这种分析与自由软件联系起来。
位图图像形式的图形在整个过程中被广泛使用。这样做是为了确保跨不同平台的结果一致。由于某些图形使用子像素渲染,因此本文最好在LCD屏幕上查看。
在我们开始探索字体光栅化中使用的各种方法之前,首先了解为什么光栅化是如此困难是很重要的。为什么计算机屏幕上的光栅化要比打印机上的光栅化更复杂呢?归根结底,这一切都取决于决心。或者,更准确地说,是每英寸的点数(DPI)。
打印机的起步价通常在300DPI左右,600DPI的情况并不少见。这意味着每英寸(2.54厘米)可能有300多个单独的圆点。然而,字体不是用点来衡量的,而是用点来衡量的:1/72英寸。其直接结果是,10pt处的特定字体将具有相同的物理尺寸,而与其光栅化的DPI无关。
虽然打印机的DPI相对较高,但计算机屏幕通常假定为96DPI,低三倍以上。这就是屏幕光栅化的困难所在。这可以用一个示例进行最好的说明:图1显示了10pt Times New Roman中的字母‘M’,分别为600、300和96DPI。从图中可以清楚地看出,96DPI不足以保持字形的形状或字母形式。
这种现象可以用信息论来解释。由于字形包含信息,因此可以将它们视为由各种频率组成的信号。奈奎斯特-香农采样定理指出,为了准确地再现信号,采样率需要至少是信号最大频率的两倍。如果采样率低于此值,则会引入失真(以混叠的形式)。在光栅化的情况下,采样率直接对应于输出设备的DPI。
图2中可以看到低DPI导致的混叠示例。
图2:10pt Times New Roman,96DPI。注意一些词干是如何比其他词干粗的,以及某些特征是如何被低估/过度强调的。
由于96DPI显然不足以进行精确的光栅化,我们只剩下两个选择。第一个方法是找到一种提高设备有效采样率的方法,第二个方法是降低字形的频率,以允许使用较低的采样率。本文中介绍的所有方法都属于这两个类别之一。
改善光栅化质量的最古老和最广泛使用的技术之一是字体提示。也称为网格拟合,提示涉及修改字形的形状,以确保它们与光栅化网格对齐。通过扭曲字形使其与像素网格对齐,降低了整体频率。可以在图3中看到字体提示的示例。
图3:10pt Times New Roman,96DPI,有(下)和没有(上)提示。还要注意提示文本和非提示文本之间的不同宽度。
暗示的文本比未提示的文本更一致。然而,这种一致性是以准确性为代价的。将字形扭曲到光栅化网格的一个不可避免的后果是它们的尺寸略有变化。这些细小的差异迅速累积到一行文本上,从而产生明显的差异,如图3所示。作者将这种现象称为字符漂移。
产生一致输出所需的提示程度取决于输出设备的DPI;低分辨率设备比高分辨率设备需要更积极的提示。攻击性暗示的后果之一--尽管这可能是必要的--是性格漂移。在分辨率超过300DPI的情况下,完全放弃字体提示是可能的。
字体提示通常通过以下两种方法之一实现。第一个步骤是让字体设计者控制提示过程。这是TrueType字体规范所采用的方法-无疑是最广泛使用的字体格式。在规范中,虚拟机用于指示光栅化器如何渲染字形。从理论上讲,这可以让设计者在像素级别上控制字形如何以不同大小的Tur01a进行光栅化。第二种方法是将提示留给字体光栅化器,即所谓的自动提示。当呈现非TrueType字体时-例如Adobe的Type1格式的字体,或者那些缺少提示说明的字体-这通常是Tur01a的唯一选项。
为了在这些方法之间进行有意义的比较,首先需要了解一些其他可用于提高光栅化质量的技术。
到目前为止,我们一直假设像素是二值的,开或关,黑或白。然而,现代计算机屏幕能够显示数百万种颜色,包括深浅不一的灰色。字体光栅化器可以通过使用一种称为抗锯齿的技术来利用这一点。顾名思义,抗混叠是一种在低频设备上采样高频信号时避免混叠不必要影响的方法。这是通过模糊信号来实现的,其效果是降低信号的最大频率。
消除锯齿文本的像素是多级的。也就是说,它们可以是黑色、白色或灰色阴影。像素的阴影取决于被字形遮罩的像素的百分比。这一概念在图4中得到了很好的演示。
图4:10pt Times New Roman中的字母‘g’,分别位于672DPI(左)和96DPI(右)。右侧字形已使用(基元)抗锯齿算法渲染,并按因子7缩放。
消除锯齿对文本行的影响可以在图5中看到。消除锯齿在保留字形形状方面做得非常好。此外,抗锯齿文本不会受到字符漂移的影响。然而,这种准确性是以牺牲清晰度为代价的-抗锯齿文本的对比度比其暗示的对应文本低得多。
图5:10pt Times New Roman,96DPI;无抗锯齿或提示(上),有提示(中),有抗锯齿(下)。
提示和消除锯齿都通过使文本更加一致来提高低分辨率下文本的可读性。暗示是以准确性为代价的,而抗锯齿是以对比度为代价的。在这一点上,要问的合乎逻辑的问题是“暗示和反走样可以结合使用吗?”答案是肯定的-通过适当的技巧,可以提示抗锯齿文本。
原则上,提示抗锯齿文本与提示单色文本完全相同。然而,在实践中,为了产生高质量的输出Tur01b,需要不同的实现。这一点的实用性取决于所采用的提示方法;当提示由字体光栅化程序而不是虚拟机执行时,会容易得多。事实上,天真地将TrueType提示与抗锯齿相结合通常会降低整体一致性!在呈现无衬线字体时最容易观察到这一点,如图6所示。
图6:96DPI时的10pt Arial;带TrueType提示(上)、带抗锯齿功能(中)、带TrueType提示和抗锯齿功能(下)。
虽然输出清晰,但缺乏一致性-某些字符(如‘w’和‘s’)是抗锯齿的,而其他字符(如‘l’)则不是。这会导致某些字符看起来比其他字符更重。这些较重的字符通常被称为肮脏。出现图6中明显的不良特征是因为反走样文本被提示为好像它是规则单色文本。(顺便说一句,这就是应用抗锯齿对整体角色漂移没有影响的原因。)。但正如上一节所确定的那样,抗锯齿文本的频率低于单色文本。因此,解决方案是使用不那么咄咄逼人的暗示。使用TrueType提示时很难做到这一点,因为虚拟机不能提供对提示过程的充分控制。然而,当使用自动提示时,这就变成了一种非常现实的可能性。
图7显示了FreeType提供的自动提示样式,FreeType是许多自由软件应用程序使用的流行字体光栅化库。
图7:96DPI下的10pt Arial以各种提示样式呈现;从上到下:无、轻微、中等和完整。应该注意,在这种特定情况下,中等和完全产生相同的结果。
在FreeType提供的自动提示样式中,轻微样式可能是最有趣的。与Medium和Full不同的是,它不会引起任何字符漂移,同时仍然提供了对常规抗锯齿的改进。虽然大多数算法同时提示x轴和y轴,但轻微的样式只提示y轴。由于字符漂移是由字形尺寸的累积误差引起的,因此它只能是x轴提示的结果;因此,只需提示y轴,就可以完全消除字符漂移。对于许多字体来说,更具侵略性的提示样式(中等和完整)比TrueType提示要好得多。
通过适当地将字体提示与抗锯齿相结合,可以两全其美。
到目前为止,我们考虑的所有技术都是通过降低文本的空间频率来实现的。子像素渲染,也称为子像素抗锯齿,是一种通过利用子像素的排列方式来提高LCD屏幕的有效分辨率(DPI)的方法。
LCD屏幕上的单个像素由红色、绿色和蓝色子像素按固定顺序(通常为RGB)组成。亚像素渲染通过利用这种固定排列来提高屏幕的有效水平分辨率。这是因为我们的眼睛对亮度的差异比色度的差异更敏感。因此,两个相邻的子像素可能具有明显不同的强度,但色度(颜色)难以区分。然而,这只适用于有限范围的亚像素差异:太小,强度看起来相同;太大,色度差异可见。
关于字体光栅化,处理大致如下:字形首先以水平分辨率的三倍进行光栅化(将子像素视为真正的像素),然后进行过滤-其目的是确保满足前述对子像素强度的约束。最后,将过滤后的图像映射到屏幕/输出设备上的适当子像素上。在Gib98中可以找到关于子像素渲染如何工作的更详细的解释。
图8:10pt Times New Roman,96DPI,垂直提示:普通抗锯齿(上)和亚像素抗锯齿(下)。
另外,值得注意的是反走样和亚像素渲染之间存在的区别。使用子像素渲染不需要使用抗锯齿。子像素渲染起作用,并且是有效的,无论要过滤的字形是否已使用抗锯齿功能渲染(宽度的三倍)。本节中的所有示例都展示了具有抗锯齿功能的子像素渲染。图14和Gib98中可以看到使用别名字形进行亚像素渲染的示例。更令人困惑的是,过滤过程本身就是抗锯齿的一种形式,这意味着过滤后,所有子像素呈现的文本都是抗锯齿的(因此被一些作者描述为彩色抗锯齿)。
在研究这篇文章的过程中,我发现很多用户(主要是在自由软件社区中)更喜欢禁用亚像素渲染,而不是常规的抗锯齿。绝大多数人这样做是因为一种叫色边的令人分心的不受欢迎的现象。这可以在图9中看到,请注意字符的边缘是如何着色的。
图9:10pt和12pt Times New Roman在96DPI下无过滤渲染-导致严重的颜色边缘。
由于过滤不当或不充分,会出现彩色条纹。如上一节所述,滤波对于归一化相邻子像素之间的差异以使它们位于特定范围内是必要的。如果不执行滤波,如图9所示,那么子像素之间可能会出现很大的差异。这方面的一个例子可以通过查看图9中的12pt字母‘f’来看到-它的左侧显示为黄色。这是因为最右边(蓝色)的子像素被字形的主干遮蔽,只有红色和绿色的子像素被照亮。因为红色和绿色结合成黄色,所以可以观察到一条彩色条纹。
最常见的解决方案是应用有限脉冲响应(FIR)滤波器。这可以被认为是加权移动平均值,由此子像素的强度是它与其周围的子像素的组合。采样的子像素数量-抽头数量-以及应用于这些子像素的权重是特定于实现的。各种FIR滤波器之间的差异可以在图10中看到。
图10:96DPI的12pt Times New Roman。从上到下:常规抗混叠;系数为[1/3,1/3,1/3]的3抽头FIR滤波器;5抽头FIR滤波器[1/16,4/16,7/16,4/16,1/16];5抽头FIR滤波器[1/9,2/9,3/9,2/9,1/9]。
图10中的所有三个FIR滤波器都成功地消除了彩色条纹。但是,文本的对比度因滤镜而异-第二个滤镜(向下第三行)产生的文本明显比其他两个滤镜清晰。这是由于中心子像素承载的4/16≈0.44权重较高,而其他滤光片的权重为1/3≈0.33,导致子像素强度之间的差异更大,因此字母形式更清晰。在许多方面,~0.45是中心亚像素的上限,在此之后,颜色边缘成为一种真正的可能性。(为了进行比较,图9中的未过滤文本可以认为具有系数[0,0,1,0,0]。)。
之所以选择图10中所示的三个过滤器,是因为它们都可以在实际应用程序中找到。前两个是由FreeType库提供的滤镜,它们被称为light和default,而第三个滤镜是在Gib98中概述的。
如上所述,FIR滤波器是像素间滤波器;这意味着它直接对子像素进行操作,而不考虑像素边界。然而,存在另一类过滤器,它们确实考虑了像素边界。这种过滤器被称为像素内过滤器。像素间过滤器和像素内过滤器之间的主要区别在于,像素内过滤器仅在过滤暗示良好的文本Rød08时有效。这一限制严重限制了像素内过滤器的范围,并使其不适合许多应用。尽管像素内过滤器在技术上处于劣势,但在许多自由软件库中,像素内过滤器仍然是默认的-因此至少值得一提。
由于子像素渲染依赖于子像素的精确排列,因此它本质上是各向异性的,即它具有方向依赖性。因此,如果文本或屏幕发生旋转,其效果将会降低。
由于显而易见的原因,应用程序中的旋转文本相对较少。不过,许多高端显示器和移动设备都支持旋转(所谓的纵向模式)。这种旋转会导致子像素沿y轴垂直堆叠,而不是沿x轴水平堆叠。虽然在光栅化器的适当支持下,可以利用新的亚像素排列,但效果现在是在垂直方向上。这效率低得多,产生的效果类似于使用y轴提示的常规抗锯齿。
不要与子像素渲染混淆,子像素定位是反走样和子像素渲染的泛化,以允许字形的分数放置。到目前为止,我们看到的所有字形-包括那些用子像素渲染光栅化的字形-都是在整个像素边界上开始和结束的。
使用消除锯齿呈现的文本看起来比单色(黑白)文本更详细的原因之一是,消除锯齿允许笔触(线条)具有分数宽度。这是通过改变像素的强度来实现的,如图4所示,其结果是笔划之间的间距也变成了分数。因此,通过将少量空间添加到字形的左侧,可以以亚像素精度对其进行定位。提供的精度程度取决于实现。虽然1/3的像素对于大多数应用来说已经足够,但理论上可以提供1/256像素的精度。
图11显示了使用子像素定位呈现的单词“智能”。虽然所有重复的字符(i、n、t、e和l)看起来都相同,但除了n之外,它们都具有不同的像素表示。这在图12中可以清楚地看到。
图11:11pt Times New Roman使用Quartz(Mac OS X的2D图形库)进行亚像素定位渲染。
亚像素定位提供的改进精度转化为字形之间更一致的间距。但是,与亚像素渲染一样,有几个重要的推论。
有趣的是,子像素定位不需要使用子像素渲染。事实上,这项技术实际上早于亚像素渲染的广泛采用!但是,子像素渲染确实提供了一种将字形移动1/3或2/3像素的方便方法。通过光栅化字形一次(宽度的三倍),然后进行预过滤,在字形的左侧插入一个或两个空间单位,就有可能产生所有三个亚像素变体。这样的技术具有不需要来自光栅化器的显式支持的理想特性,并且甚至可以用于亚像素位置单色文本,无论是暗示的还是其他的。
呈现字形是一项计算量很大的操作。因此,大多数光栅化程序都会保存或缓存以特定大小渲染特定字形的结果。然而,子像素定位的结果之一是,字形可以具有多个像素表示,每个表示需要其自己的高速缓存条目。这既增加了字形高速缓存的大小,又降低了其效率。例如,支持1/3像素定位的光栅化器理论上需要的内存是不使用子像素定位的光栅化器的三倍。因此,光栅化提供合理的精确度是很重要的。
大体上,桌面应用程序可以分为两类:需要可自由缩放文本的应用程序和不需要可自由缩放文本的桌面应用程序。如果文本的度量在缩放下是线性的,则称文本是可自由缩放的。或者,换句话说,字形在屏幕上的位置和间距与在纸张上完全相同-而不考虑DPI的差异。
可自由缩放的文本是最常见的。
..