OpenType字体规范解析(三)cmap表
我们在设计中经常需要使用字体文件,有时候会想一窥究竟字体文件到底是以怎样的格式存储的,OpenType就是定义字体文件存储格式的规范。
这篇文章介绍了cmap表。
cmap表定义了字符代码到字形索引的映射。字符代码如果没有对应任何字形,应映射到字形索引0,该位置上的字形必须是一个特殊的字形,表示缺失字符,通常称为 .notdef。
每个子表有七种可能的格式之一,并以一个格式字段开始,指示所使用的格式。前四种格式——格式 0、2、4 和 6——最初是在 Unicode 2.0 之前定义的。这些格式支持 8 位单字节、8 位多字节和 16 位编码。随着 Unicode 2.0 引入的补充平面,Unicode 可寻址的编码空间扩展到了 16 位以上。为了适应这种变化,添加了三种新的格式——格式 8、10 和 12——它们支持 32 位编码方案。
Unicode 的其他增强特性导致了其他子表格式的添加。子表格式 13 允许将许多字符映射到一个字形,这对于“最后备用”字体非常有用,后者为所有可能的 Unicode 字符提供回退渲染,并为不同的 Unicode 范围提供不同的回退字形。子表格式 14 提供了一个统一的机制,用于支持 Unicode 变体序列。
在七种可用格式中,并不是所有格式都常用。格式4或12适用于大多数新字体,具体取决于支持的 Unicode 字符集。
以下我们会详细解析一下格式4和12。
cmap表结构
cmap由表头与子表数据两个部分构成。其中表头包括子表数量,与每个子表的编码概要。
表头格式
类型 | 名称 | 描述 |
---|---|---|
uint16 | version | 表的版本号 |
uint16 | numTables | 子表数量 |
EncodingRecord | encodingRecords[numTables] |
EncodingRecord格式:
类型 | 名称 | 描述 |
---|---|---|
uint16 | platformID | 平台ID |
uint16 | encodingID | 编码ID |
Offset32 | subtableOffset | 子表的字节偏移量 |
格式4子表
cmap表格式4子表专门用于映射 Unicode 字符到字形索引。它使用 Segmented Coverage 结构,通过多个编码段(segments)来描述字符集中的编码映射。格式4子表使用了一种分段的方式,将字符编码范围分为不同的段(segments),每个段有自己的字形映射。每个段包含一个连续的字符编码范围,并且这个范围中的所有字符都可以映射到特定的字形或按一定的规则进行映射。
类型 | 名称 | 描述 |
---|---|---|
uint16 | format | 子表格式标识,始终为 4。 |
uint16 | segCountX2 段的数量的两倍,表示有多少个编码段。 | |
uint16[] | endCount 每个段的结束编码点,是一个 segCount 长度的数组。每个段的结束字符编码。 | |
uint16[] | reservedPad 保留字节,长度为 2 字节,必须设置为 0。 | |
uint16[] | startCount 每个段的起始编码点,是一个 segCount 长度的数组。每个段的起始字符编码。 | |
uint16[] | idDelta 每个段的字形索引增量,是一个 segCount 长度的数组。 | |
uint16[] | idRangeOffset 每个段的字形索引偏移量,是一个 segCount 长度的数组。 | |
uint16[] | glyphIdArray 字形 ID 数组,包含所有映射的字形,或者偏移后的字形 ID(根据 idRangeOffset 和 idDelta)。 |
格式12子表
cmap表格式12子表是为了解决Unicode超过16位地址空间的需求而设计的,它支持 32 位字符编码 的直接映射,主要用于Unicode的扩展平面(Supplementary Planes),也称为补充平面字符。这种格式适用于需要完整支持Unicode字符集的字体。
类型 | 名称 | 描述 |
---|---|---|
uint16 | format | 子表格式标识,始终为 12。 |
uint16 | reserved | 保留字段,必须设置为 0。 |
uint32 | length | 子表的总长度(以字节为单位),从子表的开头算起。 |
uint32 | language | 指定子表使用的语言系统;大多数情况下设置为 0。 |
uint32 | nGroups | 分组的数量,定义了有多少个编码范围(段)。 |
GroupRecord[] | groups | 分组记录的数组,每个分组描述一个字符编码范围及其映射的字形索引。 |
每个分组记录 (GroupRecord) 描述一个连续的字符编码范围,并为这些编码指定一个起始的字形索引。
GroupRecord结构:
类型 | 名称 | 描述 |
---|---|---|
uint32 | startCharCode | 字符编码范围的起始值(包含)。 |
uint32 | endCharCode | 字符编码范围的结束值(包含)。 |
uint32 | startGlyphID | 与 startCharCode 对应的字形索引。后续字符依次递增映射到字形索引。 |
注:文章包含AI辅助生成内容,如无意中使用了您的数据,请联系笔者进行处理。
小广告
笔者开源了一款字体设计工具,可以设计字体轮廓并生成otf字体文件,欢迎来玩。源码地址:
github: https://github.com/HiToysMaker/fontplayer
gitee: https://gitee.com/toysmaker/fontplayer