字体介绍

本篇文章主要翻译freetype官网上有关字体的介绍。

一、基本的排版概念

1、字体文件、格式和信息(Font files, format and information)

font是用于显示或打印的文字的图像集合。在某一个font中的图像拥有一些共同的属性,如外观、风格、衬线等。就排版而言,我们必须清楚分辨font family和font face的区别。例如,‘Palatino Regular’ 和’Palatino Italic’ 是出自同一个font family的两个不同的font face, 并且都可以被称之为‘Palatino’。
术语“font”,通常用于不必清楚区分family和face的时候,当然具体也要区分语境。大多数的families是由几个不同的文件来实现的,如,TrueType字体通常使用单独的一个被称之为font的文件来表示一种face,如arial.ttf 表示 ‘Arial Regular’, ariali.ttf 表示‘Arial Italic’。
因而,digital font就是包含了一个或者多个font faces的数据文件,每一个文件中都包含有文字图像、文字的度量以及其他一些对文字编码和布局非常重要的信息。在一些文字格式(format)中,例如Adobe的Type 1,某种font face是用几个文件共同描述的(如,某个文件存储字形图像,另一个文件存储字形的度量)。FreeType 2能够正确地处理多个文件构成的字体,但是我们在接下来的文档中会忽略掉这些实现细节,并且认为digital font就是一个文件。
方便起见,我们将包含多个face的字体文件称之为字体集(font collection)。通常这种情况在西文中较少见,但是在一些亚洲字体中却又很常见,因为这些字体通常会有水平和竖直两种布局方式。

2、文字图像和映射(Character images and mappings)

文字图像被称之为字形(glyph)。出于所使用的脚本、用途或者使用环境的考虑等,某一个字形可以有不同的图像表示,而且不同的文字也可以拥有相同的图像表示,如,罗马连写 ‘fi’ and ‘fl’就是同一个字形图像。文字和字形之间的关系是非常复杂的,我们不做继续讨论。此外,一些字体格式或多或少使用了复杂的模式(scheme)来存储和获取字形,而为了简洁起见,我们在谈论FreeType时只保留如下的一些概念:

  • 一个字体文件中包含了一个字形的集合;每一个字形被存储为bitmap、矢量表示(a vector representation),或者其他任何模式(scheme)(大多数可缩放格式都是用了数学表示和控制数据/程序相结合的方式)。这些字形可以存储在字体文件的任意位置,而且一般都能通过简单的索引获取。
  • 字体文件包含一个或者多个表,称之为文字映射(character maps,‘charmaps’,‘cmaps’),用于将给定编码的文字码转换成字形的索引。某个字体face可能包含多个charmaps。一个font face中可以包含多个charmaps,如,许多TrueType字体包含了Apple特定的和Unicode特定的charpmap,以便于经字体应用与Mac平台和Windows平台。

3、文字和字体度量(Character and font metrics)

每个字形图像都关联着许多度量值来描述如何放置字形以及如何管理文字渲染;度量值与字形的位置、光标的步进以及文字的布局相关,而这些值在渲染文字流时是及其重要的。
每种可缩放的字体格式还包含一些用概念性的(如字体)单位表示的全局度量,用以同一个face中字形的一些属性。比如,最大字形边界盒、升高、降低和字体中文字的高度。
不可缩放的文字也有一些度量,但是仅用于给定的文字维度和分辨率,而且通常的单位是像素点。

二、字形轮廓(Glyph Outlines)

该部分描述了字形图像的可缩放表示,称之为轮廓(outline)。

三、字形度量(Glyph Metrics)

1、基线、画笔和布局(baseline、pens and layout)

基线是一条假想出来的线,在渲染字体的时候起参照作用。基线可以是水平的,也可以是竖直的,例如拉丁文一般是水平排版的,而一些中文、日文有时却是竖直排版的。此外,我们假想在基线上存在一个点,称之为画笔位置或者原点(origin),并用这个点来定位每个字形。

  • 水平布局中,字形总是坐落在基线上。文字在渲染时,无论是从左到右还是相反方向,都是通过递增画笔位置来完成的。
    连续的两个画笔之间的距离是由特定的字形决定的,比如下图中’A’ ‘b’ 's’的宽度都不一样,我们将这个画笔距离称之为“步进宽度”(advance width)。值得注意的是,即使在渲染一些RTL(right to left)文字(如阿拉伯语)时,步进宽度也是一个正数值,所不同的只是文字渲染的方式。
    字体介绍_第1张图片
  • 对于水平布局,字形在基线两侧匀称分布,如下图所示:
    字体介绍_第2张图片

板式度量和边界盒(Typographic metrics and bounding boxes)

一个给定字体中的字形需要用到很多度量值来描述。

  • Ascent
    从基线到用于放置轮廓点(outline point)的网格坐标最高点的距离。因为网格坐标的Y轴是竖直向上的,因而它是一个正值。
  • Descent
    从基线到用于放置轮廓点的网格坐标的最低点的距离。在FreeType中,由于网格坐标的Y轴方向是竖直向上的,所以该值是个负数值。注意,在某些字体格式中该值为正值。
  • Linegap
    两行文字之间的距离,即行间距。基线到基线的距离按如下方式计算:
    linespace = ascent - descent + linegap

另外,还有一些更简单的度量:

  • Bounding box
    这是一个想象中的将字形尽可能紧密包裹起来的盒子,它用四个值表示,xMinyMinxMaxyMax。这些值在原始轮廓(original outline)中可以用字体单位(font units)度量,或者在缩放轮廓中(scaled outline)使用整型像素单位来度量。
  • Internal leading
    这一概念直接来源于传统的排版界,它表示一个字形的前导空间的大小,前导空间是位于EM方块之外的为一些字形特性而保留的,如重音标记,通常可以由如下方式计算:
    internal leading = ascent - descent - EM_size
  • External leading
    行间距的另一种叫法。

轴承和步进(bearings and advances)

每一个字形都有称为轴承和步进的距离量。鉴于字形既可以被渲染成水平方向的也可以被渲染成竖直方向的,因而这些标量的值取决于字体的布局方式。

  • Left side bearing
    从当前画笔位置到字形的边界盒的左边界的距离。对于水平布局,该值是正值,对于竖直布局,该值是负值。
    在FreeType API中,该值被称为bearingX,另一种简称为lsb
  • Top side bearing
    从基线到字形边界盒最顶部的竖直距离。对于水平布局,该值为正,对于竖直布局,该值为负。
    在FreeType API中,该值被称为bearingY
  • Advance width
    当处理一串文字时,对于LTR书写习惯,是字形与字形间的水平增加距离量,对于RTL书写习惯,则是字形与字形之间水平减少的距离量。在水平布局时,该值为正值,竖直布局时,该值为零。
    在FreeType API中,该值被称为advanceX
  • Advance height
    在渲染完一个字形后,画笔位置在水平方向上的增加量。于竖直布局而言是个正值,于水平布局而言总是零。
    在FreeType API中,该值被称为advanceY
  • Glyph width
    字形的水平方向宽度。对于未缩放的字体坐标而言,
    glyph width = bbox.xMax - bbox.xMin
    对于已缩放的字形,计算该值需要特殊的处理,具体见grid-fitting章节。
  • Glyph height
    字形的竖直高度。对于猥琐方的字体坐标,
    glyph height = bbox.yMax - bbox.yMin
    对于缩放的字形,计算该值需要特殊的处理,具体见grid-fitting章节。
  • Right side bearing
    只在水平布局中用于描述边界盒右边界到步进宽度的距离。大多数情况下是一个非负值:
    right side bearing = advance_width - left_side_bearing - (xMax-xMin)
    一般简记为rsb
    字体介绍_第3张图片
    字体介绍_第4张图片

四、字距(Kerning)

五、文本处理(Text Process)

该部分主要介绍渲染文本的算法,这些算法使用了前面介绍的概念并且不必考虑文字布局的因素。我们假设所要渲染的文本是简单文本(simple text),例如拉丁文字系统或是西里尔文字系统,这些文字系统输入的文字码和输出的字形索引间是一对一的关系,而不像阿拉伯文字系统或者高棉文字系统需要额外的塑性引擎(shaping engine)支持才能完成文字码到字形索引的转换,当然,这些特殊文字系统并不在下面的讨论之列。

1、书写简单的文本字串(Writing simple text strings)

在第一个例子中,我们会产生一个简单的拉丁文字系统的文本字串,例如水平方向上从左到右布局。使用独特的像素度量,整个过程如下:

  1. 将文字串转换成字形索引序列;
  2. 将画笔放置到光标位置;
  3. 获取或者加载字形图像;
  4. 平移字形并使得字形的“原点”与画笔位置重合;
  5. 将字形渲染到特定设备上;
  6. 以字形的步进宽度(像素单位表示)为度量增加画笔位置;
  7. 为下面的每个字形重复3~6步骤;
  8. 当所有的字形渲染完毕,设置文本光标为新的画笔位置。
    注意:该算法并未考虑到字间距。

2、伪子像素定位(Pseudo-subpixel positioning)

使用子像素定位有时会很有用。这时的文本渲染过程与1小节类似,只有如下些许不同:

  • 画笔位置被表示为小数像素;
  • 因为平移一个微调后的并且以小数表示距离的轮廓时会破坏grid-fitting,在渲染文字图像之前,字形原点的位置必须取整。
  • 步进宽度一小数表示,并且不一定是整数。
    所以,就有如下改进的算法版本:
  1. 将文字串转换成字形索引序列;
  2. 将画笔放置到光标位置,可以是非整数点;
  3. 获取或者加载字形图像;
  4. 平移字形并使得字形的“原点”与取整后的画笔位置重合;
  5. 将字形渲染到特定设备上;
  6. 以字形的小数表示的步进宽度(像素单位表示)为度量增加画笔位置;
  7. 为下面的每个字形重复3~6步骤;
  8. 当所有的字形渲染完毕,设置文本光标为新的画笔位置。
    注意:在使用小数像素位置时,字母之间的空间并非固定的,而是取决于在之前字形定位过程中产生的舍入误差的累加值。对于自动微调的字形而言,这一问题可以使用lsb_deltarsb_delta来缓和。

3、简单的字间距(Simple kerning)

为简单的文本字串增减字间距非常简单:当发现字间距对(kerning pair)时,在步骤4前简单地将缩放后的字间距增加到画笔位置上即可,注意虽然在算法2中不必要取整,但在算法1中这一距离应当是取整后的值。

4、从右向左布局(Right-to-left layout)

处理从右向左布局的文字系统时(如希伯来文字系统)与上述的处理过程非常相似。唯一的区别在于,在字形渲染前画笔位置要减去一个步进宽度(记住:即使是希伯来字形,步进宽度也一定时正值)。

5、竖直布局(Vertical layout)

排版竖直文本的过程与前面说的一样,只有如下的区别:

  • 基线时竖直的,必须用竖直度量替换水平度量;
  • 左轴承通常是负值,但是字形的原点还是一定坐落在基线上;
  • 步进高度始终是正值,所以如果有谁想要从下向上书写,画笔位置必须减去步进高度(假定Y轴是向上的)。

六、FreeType轮廓(FreeType outlines)

七、FreeType位图(FreeType Bitmaps)

你可能感兴趣的:(字体介绍)