《FreeType Glyph Conventions》中译版

官方文档: http://www.freetype.org/freetype2/documentation.html

FreeType字形约定

一、基本印刷概念 1、字体文件、格式和信息 字体是一组可以被显示和打印的多样的字符映像,在单个字体中共享一些共有的特性,包括外表、风格、衬线等。按印刷领域的说法,它必须区别一个字体家族和多种字体外观,后者通常是从同样的模板而来,但是风格不同。例如,Palatino Regular 和 Palatino Italic是两种不同的外观,但是属于同样的家族Palatino。

单个字体术语根据上下文既可以指家族也可指外观。例如,大多文字处理器的用户用字体指不同的字体家族,然而,大多这些家族根据它们的格式会通过多个数据文件实现。对于 TrueType来讲,通常是每个外观一个文件(arial.ttf对应Arial Regular外观,ariali.ttf对应Arial Italic外观)这个文件也叫字体,但是实际上只是一个字体外观。

数字字体是一个可以包含一个和多个字体外观的数据文件,它们每个都包含字符映像、字符度量,以及其他各种有关文本布局和特定字符编码的重要信息。对有些难用的格式,像Adobe的Type1,一个字体外观由几个文件描述(一个包含字符映象,一个包含字符度量等)。在这里我们忽略这种情况,只考虑一个外观一个文件的情况,不过在FT2.0中,能够处理多文件字体。

为了方便说明,一个包含多个外观的字体文件我们叫做字体集合,这种情况不多见,但是多数亚洲字体都是如此,它们会包含两种或多种表现形式的映像,例如横向和纵向布局。

2、字符映象和图 字符映象叫做字形,根据书写、用法和上下文,单个字符能够有多个不同的映象,即多个字形。多个字符也可以有一个字形(例如Roman??)。字符和字形之间的关系可能是非常复杂,本文不多述。而且,多数字体格式都使用不太难用的方案存储和访问字形。为了清晰的原因,当说明FT时,保持下面的观念

  • 一个字体文件包含一组字形,每个字形可以存成位图、向量表示或其他结构(更可缩放的格式使用一种数学表示和控制数据/程序的结合方式)。这些字形可以以任意顺序存在字体文件中,通常通过一个简单的字形索引访问。

  • 字体文件包含一个或多个表,叫做字符图,用来为某种字符编码将字符码转换成字形索引,例如ASCII、Unicode、Big5等等。单个字体文件可能包含多个字符图,例如大多TrueType字体文件都会包含一个Apple特定的字符图和Unicode字符图,使它在Mac和Windows平台都可以使用。

3、字符和字体度量 每个字符映象都关联多种度量,被用来在渲染文本时,描述如何放置和管理它们。在后面会有详述,它们和字形位置、光标步进和文本布局有关。它们在渲染一个文本串时计算文本流时非常重要。

每个可缩放的字体格式也包含一些全局的度量,用概念单位表示,描述同一种外观的所有字形的一些特性,例如最大字形外框,字体的上行字符、下行字符和文本高度等。

虽然这些度量也会存在于一些不可缩放格式,但它们只应用于一组指定字符维度和分辨率,并且通常用象素表示。

二、字形轮廓 1、象素、点和设备解析度 当处理计算机图形程序时,指定象素的物理尺寸不是正方的。通常,输出设备是屏幕或打印机,在水平和垂直方向都有多种分辨率,当渲染文本是要注意这些情况。

定义设备的分辨率通常使用用dpi(每英寸点(dot)数)表示的两个数,例如,一个打印机的分辨率为300x600dpi表示在水平方向,每英寸有300 个象素,在垂直方向有600个象素。一个典型的计算机显示器根据它的大小,分辨率不同(15’’和17’’显示器对640x480象素大小不同),当然图形模式分辨率也不一样。

所以,文本的大小通常用点(point)表示,而不是用设备特定的象素。点是一种简单的物理单位,在数字印刷中,一点等于1/72英寸。例如,大多罗马书籍使用10到14点大小印刷文字内容。

可以用点数大小来计算象素数,公式如下:

象素数 = 点数*分辨率/72

分辨率用dpi表示,因为水平和垂直分辨率可以不同,单个点数通常定义不同象素文本宽度和高度。

2、向量表示 字体轮廓的源格式是一组封闭的路径,叫做轮廓线。每个轮廓线划定字形的外部或内部区域,它们可以是线段或是Bezier曲线。

曲线通过控制点定义,根据字体格式,可以是二次(conic Beziers)或三次(cubic Beziers)多项式。在文献中,conic Bezier通常称为quadratic Beziers。因此,轮廓中每个点都有一个标志表示它的类型是一般还是控制点,缩放这些点将缩放整个轮廓。

每个字形最初的轮廓点放置在一个不可分割单元的网格中,点通常在字体文件中以16位整型网格坐标存储,网格的原点在(0,0),它的范围是-16384到-16383(虽然有的格式如Type1使用浮点型,但为简便起见,我们约定用整型分析)。

网格的方向和传统数学二维平面一致,x轴从左到右,y轴从下到上。

在创建字形轮廓时,一个字体设计者使用一个假想的正方形,叫做EM正方形。他可以想象成一个画字符的平面。正方形的大小,即它边长的网格单元是很重要的,原因是

  • 它是用来将轮廓缩放到指定文本尺寸的参考,例如在300x300dpi中的12pt大小对应12*30072=50象素。从网格单元缩放到象素可以使用下面的公式

象素数 = 点数 × 分辨率/72 象素坐标= 网格坐标*象素数/EM大小

  • EM尺寸越大,可以达到更大的分辨率,例如一个极端的例子,一个4单元的EM,只有25个点位置,显然不够,通常TrueType字体之用2048单元的EM;Type1 PostScript字体有一个固定1000网格单元的EM,但是点坐标可以用浮点值表示。

注意,字形可以自由超出EM正方形。网格单元通常交错字体单元或EM单元。上边的象素数并不是指实际字符的大小,而是EM正方形显示的大小,所以不同字体,虽然同样大小,但是它们的高度可能不同。

3、Hinting和位图渲染 存储在一个字体文件中的轮廓叫“主”轮廓,它的点坐标用字体单元表示,在它被转换成一个位图时,它必须缩放至指定大小。这通过一个简单的转换完成,但是总会产生一些不想要的副作用,例如像字母E和H,它们主干的宽度和高度会不相同。

所以,优秀的字形渲染过程在缩放“点”是,需要通过一个网格对齐(grid-fitting)的操作(通常叫hinting),将它们对齐到目标设备的象素网格。这主要目的之一是为了确保整个字体中,重要的宽度和高度能够一致。例如对于字符I和T来说,它们那个垂直笔划要保持同样象素宽度。另外,它的目的还有管理如stem和overshoot的特性,这在小象素字体会引起一些问题。

有若干种方式来处理网格对齐,多数可缩放格式中,每种字形轮廓都有一些控制数据和程序。

  • 显式网格对齐

TrueType格式定义了一个基于栈的虚拟机(VM),可以借助多于200中操作码(大多是几何操作)来编写程序,每个字形都由一个轮廓和一个控制程序组成,后者可以处理实际的网格对齐,他由字体设计者定义。

  • 隐式网格对齐(也叫hinting)

Type1格式有一个更简单的方式,每个字形由一个轮廓以及若干叫hints的片断组成,后者用来描述字形的某些重要特性,例如主干的存在、某些宽度匀称性等诸如此类。没有多少种hint,要看渲染器如何解释hint来产生一个对齐的轮廓。

  • 自动网格对齐

有些格式很简单,没有包括控制信息,将字体度量如步进、宽度和高度分开。要靠渲染器来猜测轮廓的一些特性来实现得体的网格对齐。

下面总结了每种方案的优点和缺点

方案 优点 缺点

显式 质量:对小字体有很好的结果,这对屏幕显示非常重要。 速度:如果程序很复杂,解释字节码很慢 一致性:所有渲染器产生同样的字形位图。 大小:字形程序会很长。 技术难度:编写优秀的hinting程序非常难,没有好的工具支持。

隐式 大小:Hint通常比显式字形程序小的多 质量:小字体不好,最后结合反走样 速度:网格对齐会非常快 不一致:不同渲染器结果不同,甚至同一引擎不同版本也不同。

自动 大小:不需要控制信息,导致更小的字体文件 质量:小字体不好,最后结合反走样 速度:依赖对齐算法,通常比显式对齐快。 速度:依赖算法 不一致:不同渲染器结果不同,甚至同一引擎不同版本也不同。

三、字形度量 1、基线(baseline)、笔(pen)和布局(layout) 基线是一个假想的线,用来在渲染文本时知道字形,它可以是水平(如Roman)和是垂直的(如中文)。而且,为了渲染文本,在基线上有一个虚拟的点,叫做笔位置(pen position)或原点(origin),他用来定位字形。

每种布局使用不同的规约来放置字形:

  • 对水平布局,字形简单地搁在基线上,通过增加笔位置来渲染文本,既可以向右也可以向左增加。

两个相邻笔位置之间的距离是根据字形不同的,叫做步进宽度(advance width)。注意这个值总是正数,即使是从右往左的方向排列字符,如Arabic。这和文本渲染的方式有些不同。

笔位置总是放置在基线上。

  • 对垂直布局,字形在基线上居中放置:

2、印刷度量和边界框 在指定字体中,定义了多种外观度量。

  • 上行高度(ascent)。从基线到放置轮廓点最高/上的网格坐标,因为Y轴方向是向上的,所以它是一个正值。

  • 下行高度(descent)。从基线到放置轮廓点最低/下的网格坐标,因为Y轴方向是向上的,所以它是一个负值。

  • 行距(linegap)。两行文本间必须的距离,基线到基线的距离应该计算成

上行高度 - 下行高度 + 行距

  • 边界框(bounding box,bbox)。这是一个假想的框子,他尽可能紧密的装入字形。通过四个值来表示,叫做xMin、yMin、xMax、yMax,对任何轮廓都可以计算,它们可以是字体单元(测量原始轮廓)或者整型象素单元(测量已缩放的轮廓)。注意,如果不是为了网格对齐,你无需知道这个框子的这个值,只需知道它的大小即可。但为了正确渲染一个对齐的字形,需要保存每个字形在基线上转换、放置的重要对齐。

  • 内部leading。这个概念从传统印刷业而来,他表示字形出了EM正方形空间数量,通常计算如下

internal leading = ascent – descent – EM_size

  • 外部leading。行距的别名。

3、跨距(bearing)和步进 每个字形都有叫跨距和步进的距离,它们的定义是常量,但是它们的值依赖布局,同样的字形可以用来渲染横向或纵向文字。

  • 左跨距或bearingX。从当前笔位置到字形左bbox边界的水平距离,对水平布局是正数,对垂直布局大多是负值。

  • 上跨距或bearingY。从基线到bbox上边界的垂直距离,对水平布局是正值,对垂直布局是负值。

  • 步进宽度或advanceX。当处理文本渲染一个字形后,笔位置必须增加(从左向右)或减少(从右向左)的水平距离。对水平布局总是正值,垂直布局为null。

  • 步进高度或advanceY。当每个字形渲染后,笔位置必须减少的垂直距离。对水平布局为null,对垂直布局总是正值。

  • 字形宽度。字形的水平长度。对未缩放的字体坐标,它是bbox.xMax-bbox.xMin,对已缩放字形,它的计算要看特定情况,视乎不同的网格对齐而定。

  • 字形高度。字形的垂直长度。对未缩放的字体坐标,它是bbox.yMax-bbox.yMin,对已缩放字形,它的计算要看特定情况,视乎不同的网格对齐而定。

  • 右跨距。只用于水平布局,描述从bbox右边到步进宽度的距离,通常是一个非负值。

advance_width – left_side_bearing – (xMax-xMin)

下图是水平布局所有的度量

下图是垂直布局的度量

4、网格对齐的效果 因为hinting将字形的控制点对齐到象素网格,这个过程将稍稍修改字符映象的尺寸,和简单的缩放有所区别。例如,小写字母m的映象在主网格中有时是一个正方形,但是为了使它在小象素大小情况下可以辨别,hinting试图扩大它已缩放轮廓,以让它三条腿区分开来,这将导致一个更大的字符位图。

字形度量也会受网格对齐过程的影响:

  • 映象的宽度和高度改变了,即使只是一个象素,对于小象素大小字形区别都很大;

  • 映象的边界框改变了,也改变了跨距;

  • 步进必须更改,例如如果被hint的位图比缩放的位图大时,必须增加步进宽度,来反映扩大的字形宽度。

这有一些含义如下,

  • 因为hinting,简单缩放字体上行或下行高度可能不会有正确的结果,一个可能的方法时保持被缩放上行高度的顶和被缩放下行高度的底。

  • 没有容易的方法去hint一个范围内字形并步进它们宽度,因为hinting对每个轮廓工作都不一样。唯一的方法时单独hint每个字形,并记录返回值。有些格式,如TrueType,包含一些表对一些通用字符预先计算出它们的象素大小。

  • hinting依赖最终字符宽度和高度的象素值,意味着它非常依赖分辨率,这个特性使得正确的所见即所得布局非常难以实现。

在FT 中,对字形轮廓处理2D变换很简单,但是对一个已hint的轮廓,需要注意专有地使用整型象素距离(意味着FT_Outline_Translate() 函数的参数应该都乘以64,因为点坐标都是26.6固定浮点格式),否则,变换将破坏hinter的工作,导致非常难看的位图。

5、文本宽度和边界框 如上所示,指定字形的原点对应基线上笔的位置,没有必要定位字形边界框的某个角,这不像多数典型的位图字体格式。有些情况,原点可以在边界框的外边,有时,也可以在里边,这要看给定的字形外形了。

同样,字形的步进宽度是在布局时应用于笔位置的增量,而不是字形的宽度,那是字形边界的宽度。对文本串,具有相同的规约,这意味着:

  • 指定文本串的边界框没有必要包含文本光标,也不需要后边的字形放置在它的角上。

  • 字符串的步进宽度和它的边界框大小无关,特别时它在开始和最后包含空格或tab。

  • 最后,附加的处理如间距调整能够创建文本串,它的大小不直接依赖单独字形度量并列排列。例如,VA的步进宽度不是V和A各自的步进之和。

四、字距调整 字距调整这个术语指用来在一个文本串中调整重合字形的相对位置的特定信息。

1、字距调整对 字距调整包括根据相邻字形的轮廓修改它们之间的距离。例如T和y可以贴得更近一点,因为y的上缘正好在T的右上角一横的下边。

当仅仅根据字形的标准宽度来布局文本,一些连续的字符看上去有点太挤和太松,例如下图中A和V的就显得距离太远。

比较一下下图,同样的单词,A和V的距离拉近些

可以看到,这个调整可以导致很大的区别。有的字体外观包含一个表,它包含文本布局所需的指定字形对的字距距离。

  • 这个对是顺序的,AV对的距离和VA对不一定一致;

  • 依据布局或书写,字距可以表示水平或垂直方向。

  • 字距表示成网格单元,它们通常是X轴方向的,意味着负值表示两个字形需要在水平方向放的更近一点。

2、应用字距调整 在渲染文本时应用字据调整是一个比较简单的过程,只需要在写下一个字形时,将缩放的字距加到笔位置即可。然而,正确的渲染器要考虑的更细一点。

“滑动点”问题是一个很好的例子:很多字体外观包括一个大写字符(如T、F)和一个点.之间的字距调整,以将点正好放置在前者的主腿的右侧。

根据字符的外形,有时候需要在点和随后的字符间作附加的调整,当应用“标准”的字距调整,上面的句子如下

这显然太紧凑了。一个方案是,只在需要时滑动点,当然这需要对文本的意思有了解。如果当我们在渲染特定段落的最后一个点时,上面的调整就不适合了。这只是一个例子,还有很多其他例子显示一个真正的印刷工人需要恰当地布局文本。

有一个很简单地算法,可以避免滑动点问题。

  1. 在基线上放置第一个字形;
  2. 将笔位置保存到pen1;
  3. 根据第一个和第二个字形的字距距离调整笔位置;
  4. 放置第二个字形,并计算下个笔位置,放到pen2;
  5. 如果pen1大于pen2,使用pen1作为下个笔位置,否则使用pen2。

五、文本处理 1、书写简单文本串 在第一个例子中,我们将生成一个简单的Roman文字串,即采用水平的自左向右布局,使用专有的象素度量,这个过程如下:

  1. 将字符串转换成一系列字形索引;
  2. 将笔放置在光标位置;
  3. 获得或装入字形映象;
  4. 平移字形以使它的原点匹配笔位置;
  5. 将字形渲染到目标设备;
  6. 根据字形的步进象素增加笔位置;
  7. 对剩余的字形进行第三步;
  8. 当所有字形都处理了,在新的笔位置设置文本光标。

注意字距调整不在这个算法中。

2、子象素定位 在渲染文本时使用子象素定位有时很有用。这非常重要,例如为了提供半所见即所得的文本布局,文本渲染的算法和上一节很相似,但是有些区别:

  • 笔位置表示成小数形式的象素;
  • 因为将一个已经hint过的轮廓平移一个非整型距离将破坏网格对齐,字形原点的位置在渲染字符映象前必须取整;
  • 步进宽度表示成小数形式的象素,没有必要是整型。

这里是算法的改进版本:

  1. 将字符串转换成一系列字形索引;
  2. 将笔放置在光标位置,这可以是一个非整型点;
  3. 获得或装入字形映象;
  4. 平移字形以使它的原点匹配取整后的笔位置;
  5. 将字形渲染到目标设备;
  6. 根据字形的步进象素宽度增加笔位置,这个宽度可以是小数形式;
  7. 对剩余的字形进行第三步;
  8. 当所有字形都处理了,在新的笔位置设置文本光标。

注意使用小数象素定位后,两个指定字符间的空间将不是固定的,它右先前的取整操作堆积的数决定。

3、简单字距调整 在基本文本渲染算法上增加字距调整非常简单,当一个字距调整对发现了,简单地在第4步前,将缩放后的调整距离增加到笔位置即可。淡然,这个距离在算法1需要被取整,算法2不必要。

4、自右向左布局 布局Arabic或Heberw文字的过程非常相似,区别只是在字形渲染前,笔位置需要减少(记住步进宽度总是正值)

5、垂直布局 布局垂直文字也是同样的过程,重要的区别如下:

  • 基线是垂直的,使用垂直的度量而不是水平度量;
  • 左跨距通常是负的,但字形原点必须在基线上;
  • 步进高度总是正值,所以笔位置必须减少以从上至下书写;

6、所见即所得布局

六、FT轮廓 1、FT轮廓描述和结构 a. 轮廓曲线分解 一个轮廓是2D平面上一系列封闭的轮廓线。每个轮廓线由一系列线段和Bezier弧组成,根据文件格式不同,曲线可以是二次和三次多项式,前者叫quadratic或conic弧,它们在TrueType格式中用到,后者叫cubic弧,多数用于Type1格式。

每条弧由一系列起点、终点和控制点描述,轮廓的每个点有一个特定的标记,表示它用来描述一个线段还是一条弧。这个标记可以有以下值:

FT_Curve_Tag_On 当点在曲线上,这对应线段和弧的起点和终点。其他标记叫做“Off”点,即它不在轮廓线上,但是作为Bezier弧的控制点。 FT_Curve_Tag_Conic 一个Off点,控制一个conic Bezier弧 FT_Curve_Tag_Cubic 一个Off点,控制一个cubic Bezier弧

下面的规则应用于将轮廓点分解成线段和弧

  • 两个相邻的“on”点表示一条线段;
  • 一个conic Off点在两个on点之间表示一个conic Bezier弧,off点是控制点,on点是起点和终点;
  • 两个相邻的cubic off点在两个on点之间表示一个cubic Bezier弧,它必须有两个cubic控制点和两个on点。
  • 最后,两个相邻的conic off点强制??在它们正中间创建一个虚拟的on点。这大大方便定义连续的conic弧。TrueType规范就是这么定义的。

注意,在单个轮廓线中可以混合使用conic和cubic弧,不过现在没有那种字体驱动产生这样的轮廓。

b. 轮廓描述符 FT轮廓通过一个简单的结构描述

FT_Outline n_points 轮廓中的点数 n_contours 轮廓中轮廓线数 points 点坐标数组 contours 轮廓线端点索引数组 tags 点标记数组

这里,points是一个FT_Vector记录数组的指针,用来存储每个轮廓点的向量坐标。它表示为一个象素1/64,也叫做26.6固定浮点格式。

contours是一组点索引,用来划定轮廓的轮廓线。例如,第一个轮廓线总是从0点开始,以contours[0]点结束。第二个轮廓线从contours[0]+1点开始,以contours[1]结束,等等。

注意,每条轮廓线都是封闭的,n_points应该和contours[n_controus-1]+1相同。最后,tags是一组字节,用来存放每个轮廓的点标记。

2、边界和控制框计算 边界框(bbox)是一个完全包含指定轮廓的矩形,所要的是最小的边界框。因为弧的定义,bezier的控制点无需包含在轮廓的边界框中。例如轮廓的上缘是一个Bezier弧,一个off点就位于bbox的上面。不过这在字符轮廓中很少出现,因为大多字体设计者和创建工具都会在每个曲线拐点处放一个on点,这会使hinting更加容易。于是我们定义了控制框(cbox),它是一个包含轮廓所有点的最小矩形,很明显,它包含bbox,通常它们是一样的。不想 bbox,cbox计算起来非常快。

控制框和边界框可以通过函数FT_Outline_Get_CBox()和 FT_Outline_Get_BBox()自动计算,前者总是非常快,后者在有外界控制点的情况下会慢一点,因为需要找到conic和cubic弧的末端,如果不是这种情况,它和计算控制框一样快。

注意,虽然大多字形轮廓为易于hint具有相同的cbox和bbox,这在它们进行变换以后,如旋转,就不再是这种情况了。

3、坐标、缩放和网格对齐 轮廓点的向量坐标表示为26.6格式,即一个象素的1/64。因此,坐标(1.0,-2.5)存放整型对(x:64,y:-192)。

在主字形轮廓从EM网格缩放到当前字符大小后,hinter负责对齐重要的轮廓点到象素网格。虽然这个过程很难几句话说清楚,但是它的目的也就是取整点的位置,以保持字形重要的特性,如宽度、主干等。下面的操作可以用来将26.6格式的向量距离取整到网格:

round(x) == (x + 32) & -64 floor(x) == x & -64 ceiling(x) == (x + 63) & -64

一旦一个字形轮廓经过对齐或变换,在渲染之前通常要计算字形的映象象素大小。做到这一点,必须考虑如下:

扫描线转换器画出所有中心在字形形状中的象素,他也可以检测drop-outs???

这导致如下的计算:

  • 计算bbox;
  • 对齐bbox如下: xmin = floor(bbox.xMin) xmax = ceiling(bbox.xMax) ymin = floor(bbox.yMin) ymax = ceiling(bbox.yMax)
  • 返回象素尺寸,即 width = (xmax-xmin) / 64 和 height = (ymax-ymin) / 64

通过对齐bbox,可以保证所有的象素中心将画到,包括那些从drop-out控制来的,将在调整后的框子之中。接着,框子的象素尺寸可以计算出来。

同时注意,当平移一个对齐的轮廓,应该总是使用整型距离来移动。否则,字形的边缘将不再对齐象素网格,hinter的工作将无效,产生非常难看的位图。

七、FT位图 1、向量坐标和象素坐标对比 这里阐述了向量坐标的象素坐标的区别,为了更清楚的说明,使用方括号来表示象素坐标,使用圆括号表示向量坐标。

在象素坐标中,我们使用Y轴向上的规约,坐标[0,0]总是指位图左下角象素,坐标[width-1, rows-1]是右上角象素。在向量坐标中,点坐标用浮点单位表示,如(1.25, -2.3),这个位置并不是指一个特定象素,而是在2D平面上一个非实质性的点。

象素其实在2D平面上是一个方块,它的中心是象素坐标值的一半,例如位图的左下角象素通过方块(0,0)-(1,1)界定,它的中心位于 (0.5,0.5)。注意这儿用的是向量坐标表示。这对计算距离就会发生一些区别。例如,[0,0]-[10.0]一条线的象素长度是11,然而, (0,0)-(10,0)的向量程度覆盖了10个象素,因此它的长度是10。

2、FT位图和象素图描述符 一个位图和象素图通过一个叫FT_Bitmap的单一结构描述,他定义在中,属性如下

FT_Bitmap rows 行数,即位图中的水平线数 width 位图的水平象素数 pitch 它的绝对值是位图每行占的字节数,根据位图向量方向,可以是正值或是负值 buffer 一个指向位图象素缓冲的无类型指针 pixel_mode 一个枚举值,用来表示位图的象素格式;例如ft_pixel_mode_mono表示1位单色位图,ft_pixel_mode_grays表示8位反走样灰度值 num_grays 这只用于灰度象素模式,它给出描述反走样灰度级别的级数,FT缺省值为255。

pitch 属性值的正负符号确定象素缓冲中的行是升序还是降序存放。上面说道FT在2D平面上使用Y轴向上的规约,这意味着(0,0)总是指向位图的左下角。如果 picth是正值,按照向量减少的方向存储行,即象素缓冲的第一个字节表示位图最上一行的部分。如果是负值,第一个字节将表示位图最下一行的部分。对所有的情况,pitch可以看作是在指定位图缓冲中,跳到下一个扫描行的字节增量。

通常都使用正pitch,当然有的系统会使用负值。

3、轮廓转换到位图和象素图 使用FT从一个向量映象转换到位图和象素图非常简单,但是,在转换前,必须理解有关在2D平面上放置轮廓的一些问题:

  • 字形转载器和hinter在2D平面上放置轮廓时,总将(0,0)匹配到字符原点,这意味着字形轮廓,及对应的边界框,可以在平面中放置于任何地方。

  • 目标位图映射到2D平面上,左下角在(0,0)上,这就是说一个[w,h]大小的位图和象素图将被映射到(0,0)-(w,h)界定的2D矩形窗口。

  • 当扫描转换轮廓,所有在这个位图窗口的部分将被渲染,其他的被忽略。

很多使用FT的开发者都会有个误解,认为一个装入的轮廓可以直接渲染成一个适当大小的位图,下面的图像表明这个问题。

  • 第一个图表明一个2D平面上一个装入的轮廓;

  • 第二个表示一个任意大小[w,h]维护的目标窗口;

  • 第三个表示在2D平面上轮廓和窗口的合并;

  • 最后一个表示位图实际被渲染的部分。

实际上,几乎所有的情况,装入或变换过的轮廓必须在渲染成目标位图之前作平移操作,以调整到相对目标窗口的位置。

例如,创建一个单独的字形位图正确的方法如下:

  • 计算字形位图的大小,可以直接从字形度量计算出来,或者计算它的边界框(这在经过变换后非常有用,此时字形度量不再有效)。

  • 根据计算的大小创建位图,别忘了用背景色填充象素缓冲;

  • 平移轮廓,使左下角匹配到(0,0)。别忘了为了hinting,应该使用整型。通常,这就是说平移一个向量(-ROUND(xMin), -ROUND(yMin))。

  • 调用渲染功能,例如FT_Outline_Render()函数。

在将字形映象直接写入一个大位图的情况,轮廓必须经过平移,以将它们的向量位置对应到当前文本光标/字符原点上。