计算机字体简介
字体分类
点阵字体
点阵字体是指每一个字符都按照16×16或24×24的尺寸设置,在设定好的尺寸内,通过每个像素点的虚实来表示字符的轮廓。点阵字体也叫位图字体,其中每个字形都以一组二维像素信息表示。
因为是预先设计好然后直接输出,当字符进行动态的放大缩小时,是无法清晰的显示字形轮廓,所以点阵字体只在预设好的字号下能清晰显示,有时候不同的字号甚至可能显示成完全不同的字体,例如(图片出处:对计算机字体渲染的一些研究):
矢量字体
矢量字体又叫做轮廓字体(Outline Fonts),是利用贝塞尔曲线来描述字形轮廓,当使用该字体时,计算机根据曲线进行实时计算渲染,从而保证了当字体进行任意大小缩放时,字符都能清晰显示。
渲染技术
无论是点阵字体还是矢量字体,在计算机中,其本质都是栅格化(Rasterization)图像。对于计算机而言,其最小操作单元就是一个个像素栅格。如何使用一定数量的像素栅格去准确描绘理想的字体形状,就是需要解决的问题。
黑白渲染(Black and white rendering)
黑白渲染又叫做二值渲染(bi-level rendering)。黑白渲染是最早人们使用的渲染技术,这种渲染方式只使用黑白两种颜色来表达文字的形状。目前打印机就仍在使用这种方法,由于打印机的高输出分辨率,打印的结果能很好地再现原图。但是由于屏幕的分辨率较低,在这种渲染方式下,放大字体可能就会看到一些锯齿。
灰度渲染(Grayscale rendering)
灰度渲染实际上是计算机图形学中的一种**反锯齿(Anti-Aliasing)**技术,通过在锯齿边缘增加一些灰阶像素,从而平滑字体轮廓。它的灰度值取决于理想的字型在此像素所覆盖的面积比例。该技术的原理与照片重新采样(resampled)到一个较低分辨率时的原理是相同的,人眼在识别图像时,由于图像的边界不明显,大脑会将其与周围的像素理解为一个整体。 因此我们的眼睛和大脑在理解灰色像素所包含的信息时,会将它转换为字型的轮廓,这就让我们可以获得与原始设计极为接近的渲染效果。
亚像素渲染(Subpixel rendering)
亚像素渲染实际上是灰度渲染的进阶版。这种技术的出现主要得益于硬件的提升。传统CRT显示器最小控制单元是像素,是由相邻的红、绿、蓝荧光粉单元各一个为一组组成。LCD液晶显示屏也是由红、绿、蓝三个子(亚)像素构成的,它们共同决定了这一像素的颜色和亮度,但LCD能够做到单独控制每一个子像素。因为这些子像素非常小,以至于人眼无法察觉到他们是一个个独立的颜色点。与单纯的灰度渲染相比,水平方向的分辨率翻了三倍。
将亚像素渲染与灰度渲染对比可以发现,视觉上来说亚像素的边缘会更平滑:
我们将这个像素细化到亚像素并转为灰度模式可以会有更直观的感受,原有的一个灰阶像素变成了三个灰阶亚像素,整个边缘进行了更加平滑的过渡:
字符编码
文字,是一个可以被人类识别的图形化符号,本质是图形,在计算机我们称之为图元。但是文字是人类文明的产物,计算机并不认识。但是对于计算机而言,它只会认识由0、1组成的二进制值,所以为了让计算机识别一段文字,需要让文字与二进制值之间进行相互转化,这个过程就是编码与解码的过程。
在计算机中存在着多种编码格式,包括ASCII编码、GB类的中文编码以及Unicode编码等,关于中文字符编码,可以查看这篇文章,本文就不做介绍,只是简单介绍一下ASCII编码和Unicode编码。
ASCII编码
ASCII码是是上个世纪60年代美国信息交换标准代码是由美国国家标准学会(American National Standard Institute , ANSI )制定的,是一种标准的单字节字符编码方案,用于基于文本的数据,对英语字符与二进制位之间的关系,做了统一规定。
ASCII规定,用8位二进制(1byte,8bit)来存储字符和特殊符号,总共可以表示256个字符。(因为英文字符总共才26个,加上特殊字符,8bit绰绰有余)。
早期只针对英文编码,是使用7 位二进制数(剩下的1位二进制为0)来表示所有的大写和小写字母,数字0 到9、标点符号,以及在美式英语中使用的特殊控制字符。此时7位的叫做标准ASCII码也叫基础ASCII码。
后来当它被国际标准化组织(International Organization for Standardization, ISO)定为国际标准后,仅仅128个符号编码就不够用了,因为在其他的拉丁文字字母中还可能存在注音符号,这时就无法用基础 ASCII 码表示。于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使用的编码体系,可以表示最多256个符号。此时把8位二进制编码的字符码称为**扩展ASCII码**。
Unicode
我们知道ASCII码最多支持256位字符,用来表示其他语言是完全不够的,亚洲国家的文字中,汉字就多达10万左右。因此出现了多种编码格式,例如GB类的中文编码。当通过多种编码方案解决了多语言的字符显示问题之后,又出现了新的问题:乱码。
我们都知道计算机内部只存储二进制数据,当我们进行通信时,发送者需要将文字编码成一串二进制比特流进行传输通信,而接收者需要使用同一套编码规则进行解码,才能获取到正确的信息。但是如果通信双方使用不同的编码规则,例如发送者使用单字节编码(规定每8位为一个字符码),而接收者使用双字节解码(规定每16位为一个字符码),或者接收者同样使用单字节编码,但是其对应的不是同一个字符,就会出现乱码。
于是Unicode就出现了。Unicode把所有语言都统一到一套编码里,每个字符在Unicode中只有唯一的字符码。
Unicode标准
Unicode标准定义 一个字符代表一个code,不存在二义性,例如U+0041总是代表'A',而且这套标准也会随着需求不断的拓展。
实质上Unicode只是一个字符集,里面是定义了所有字符和二进制code的对应关系,但是并没有真正实现字符集的编码。而UTF-8,UTF-16,UTF-32就是Unicode的不同实现。
UTF-8
UTF-8 是在互联网上使用最广的一种 Unicode 的实现方式之一。UTF-8 最大的一个特点,就是它是一种变长的编码方式,根据不同的Unicode字符,使用不同数量的字节编码。因为如果采用单字节编码方式,是不够的,而如果采用多字节编码,那么对于小序的字符来说,会在前面填充非常多的0,非常浪费空间。所以用一种可变的方式,既可以有效的利用空间,又可以包含更多数量的字符。
UTF-8 的编码规则很简单,只有二条:
1)对于单字节的符号,字节的第一位设为
0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。2)对于
n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。下表总结了编码规则,字母
x表示可用编码的位。Unicode符号范围 | UTF-8编码方式 (十六进制) | (二进制) ----------------------+--------------------------------------------- 0000 0000-0000 007F | 0xxxxxxx 0000 0080-0000 07FF | 110xxxxx 10xxxxxx 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
UTF-16
Unicode编码中,最常用的字符其实是0-65535,因此针对这点产生了UTF-16方案。
UTF-16编码以16位无符号整数为单位,将0–65535范围内的字符编码成2个字节,超过这个的用4个字节编码。UTF16编码是Unicode最直接的实现方式,通常我们在windows上新建文本文件后保存为Unicode编码,其实就是保存为UTF16编码。
UTF-32
UTF-32是Unicode的一种实现方式. UTF32编码使用固定的4个字节来存储。 因此,非常浪费空间,不利于网络传输,所以使用不普遍。
字体文件
常见的字体文件格式
我们知道,字体分为点阵字体和矢量字体。
对于纯点阵字体,其常见的字体格式包括: bdf,pcf,fnt,hbf 。
对于矢量字体,其常见的格式包括Type1,TrueType(ttf)和OpenType(otf / ttf)。
简单介绍一下矢量字体中各个格式之间的的区别:
-
Type1:全称PostScript Type1,是1985年由Adobe公司提出的一套矢量字体标准,使用贝塞尔曲线描述字形,称为PostScript曲线。是非开放字体,使用需要收费。
-
TrueType:TrueType是1991年由苹果(Apple)公司与 微软(Microsoft)公司联合提出另一套矢量字标准。虽然与Type1都是使用贝塞尔曲线描述字体轮廓,但是Type1使用三次贝塞尔曲线来描述字形,而TrueType使用的是二次贝塞尔曲线(TrueType曲线)。TrueType 曲线可接受典型的 hinting,可告知栅格化引擎在栅格化之前应该如何把轮廓扭曲,这样可精确控制字体的抗锯齿结果。
-
Opentype:是1995年由微软(Microsoft)和 Adobe公司开发的另外一种字体格式 ,基于TrueType扩展,内部兼容了TrueType 曲线和 PostScript 曲线。并且真正支持 Unicode的字体,最多可以支持 65535 个码位。其后缀名可以是ttf或者otf。仅包含TrueType 曲线,其后缀名一般是ttf,包含有 PostScript 曲线的,后缀名则是otf。
而目前常见的用于web的字体格式,除了主流的otf 和 ttf之外,还包括了WOFF 和 SVG。
WOFF:WOFF (Web Open Font Format) 本质上是 metadata + 基于 SFNT 的字体(如 TTF、OTF 或其他开放字体格式)。该格式完全是为了 Web 而创建,由 Mozilla 基金会、微软和 Opera 软件公司合作推出。 WOFF 字体均经过 WOFF 的编码工具压缩,文件大小一般比 TTF 小 40%,加载速度更快,可以更好的嵌入网页中。metadata 允许在字体文件中包含许可数据,以解决版权问题。这是万维网联盟提(qing)倡(ding)的,所以毫无疑问的是字体格式的未来。目前主流的浏览器的新版本几乎都支持 WOFF。
SVG:SVG (Scalable Vector Graphics font) 字体格式使用 SVG 的字体元素定义。这些字体包含作为标准 SVG 元素和属性的字形轮廓,就像它们是 SVG 映像中的单个矢量对象一样。SVG 字体最大的缺点是缺少字体提示(font-hinting)。字体提示是渲染小字体时为了质量和清晰度额外嵌入的信息。同时,SVG 对文本(body text)支持并不是特别好。因为 SVG 的文本选择(text selection)目前在 Safari、Safari Mobile 和 Chrome 的一些版本上完全崩坏,所以你不能选择单个字符、单词或任何自定义选项,你只能选择整行或段落文本。
TrueType 字体
目前最常使用的主流字体格式还是ttf。所以简单了解一下TrueType 字体文件结构。
TrueType 字体是一个矢量字体格式。对于矢量字体来说,要准确绘制一个字体,其文件中需要存储其图元轮廓的定义,字符代码与图元的映射等信息。所以在TrueType字体文件中,存储了多张表格,不同的表格包含了与字体相关的不同信息,下表包含了部分表格说明:
| 表名 | 说明 | 说明 |
|---|---|---|
| head | 字体头 | 字体的全局信息 |
| cmap | 字符代码到图元的映射 | 把字符代码映射为图元索引 |
| glyf | 图元数据 | 图元轮廓定义以及网格调整指令 |
| maxp | 最大需求表 | 字体中所需内存分配情况的汇总数据 |
| mmtx | 水平规格 | 图元水平规格 |
| loca | 位置表索引 | 把元索引转换为图元的位置 |
| name | 命名表 | 版权说明、字体名、字体族名、风格名等等 |
| hmtx | 水平布局 | 字体水平布局星系:上高、下高、行间距、最大前进宽度、最小左支撑、最小右支撑 |
| kerm | 字距调整表 | 字距调整对的数组 |
| post | PostScript信息 | 所有图元的PostScript FontInfo目录项和PostScript名 |
| PCLT | PCL 5数据 | HP PCL 5Printer Language 的字体信息:字体数、宽度、x高度、风格、记号集等等 |
| hhea | mac下渲染数据 | 水平布局排列字符的字体所需的信息 |
| OS/2 | OS/2和Windows特有的规格 | TrueType字体所需的规格集 |
其中对于文本的排版布局来说,有几个参数比较重要:
-
head表中的
unitsPerEm字段代表字形中UPM值 -
hhea表中的
ascent、descent和line gap字段常用于Mac OS下的字体渲染。 -
OS/2表中
- 用于window字体渲染
usWinAscentusWinDescent
- 用于印刷
sTypoAscendersTypoDescendersTypoLineGapsCapHeightsxHeight
- 用于window字体渲染
这些参数主要用于排版布局的计算。对于前端而言,在CSS行框计算中,这是最根本的依据。但是这些参数究竟代表了什么含义呢?在这里做一个简单的介绍。
em square (UPM)
em框,也叫做upm(units per em)。在字体设计中,一个字符图形需要设计到在一个框内,这个框我们称之为em框。em框的概念最早来自印刷。
在传统的金属字模中,每个字符被放置在一个统一大小的金属块中,每个字符的高度是统一的,这样每个字模可以整齐地放进行和块中(如下)。
字模的高度被称为
em,起源于大写的字符“M”的宽度;这个字母的比例被做成了方形(因此有了“EM Square”的称呼)。
em size是根据字模计算出的点值。是字符占用空间的数字化定义总量,通常指代高度,表示当前字体的字符在设计时的单位量。在OpenType字体中,UPM或em大小通常是1000单位。在TrueType字体中,UPM约定是2的幂,通常是1024或2048。而我们设置字号大小,实际上是在设置em框,从而实现缩放字符的效果。
下图的字体是在1000单位的em框中设计,其中这个 H 字符在设计时总高度为700单位,占整个框高度的 7/10,那么当给这个字符设置10px时,其实是规定了em的大小为10px,那么此时 H 的实际高度就是7px:
font Metrics
简单来说,**字体度量(Font Metrics)**就是描述一个字体的一系列参数,用于计算机解析渲染字体。在设计一套字体时,可以对这些参数进行自定义设置从而实现自定义字体设计。这些参数包含了一个字体中各个字形的轮廓参数,字符的大小,样式设置,以及该字体中字符与字符间的排布等,可以通过glossary 来了解相关的设计参数信息与含义。
而这一些系列的参数中,重点介绍一下与字符排布相关的参数(这些参数都是以英文字符为参考对象):
| 参数 | 定义 |
|---|---|
| baseline | 是文字绘制时所参照的基准线,所有的文字以此为基准位置进行设计。 |
| x-height | 小写字母的高度,以x为例 |
| capital height | 基线到大写字母顶部到高度 |
| ascent | 小写字母中延伸到 x-height以上的部分 |
| descent | 小写字母中延伸到 x-height以下 的部分 |
| leading / line gap | 从基线到基线的文本行之间的垂直间隔 |
| midline | 位于小写字母的主体之上,基线和中线之间的距离是x-height |
| spacing | 字间距 |
通过一张图来了解这些参数(图源网络):
参考
A Closer Look At Font Rendering
Font smoothing, anti-aliasing, and sub-pixel rendering
【字符编码系列】常用的几种字符编码(GBK,UTF-8,UTF-16)