“cmap”表将字符代码映射到字形索引。特定字体的编码选择取决于预期平台使用的约定。要在具有不同编码
约定的多个平台上运行的字体需要多个编码表。因此,“cmap”表可能包含多个子表,每个子表对应一个受支
持的编码方案。
1、任何一个找不到与它相对应的字形数据字节码值,那么就映射到index 0;
2、在字体的文件中必须有一个特殊的字形来表示一个未定义的字符,通常是一个方框;
3、不要将字符代码映射到字形索引-1,该索引是在处理过程中保留的一个特殊值,用于指示从字形流中
删除的字形的位置。
UInt16 platformID //平台ID
UInt16 platformSpecificID //编码ID
UInt32 offset //字节偏移值
平台ID
Platform Description
0 Unicode Indicates Unicode version.
1 Macintosh Script Manager code.
2 (reserved; do not use)
3 Microsoft Microsoft encoding.
编码ID
Format 6
格式6用于将16位、2字节的字符映射到字形索引。它有时被称为修剪后的表映射。当字体的字符代码落入单
个连续范围时,应该使用它。这导致了所谓的密集映射。没有密集映射的双字节字体(由于其多个连续范围)
应该使用Format 4。字符-字形索引映射子表格式6如下表所示:
UInt16 format // 6
UInt16 length //该格式下总的字节数 Length in bytes
UInt16 language //编码语言 Language code (see above)
UInt16 firstCode //第一个该范围内的字符代码值
//irst character code of subrange
UInt16 entryCount //该范围内字符的个数
//Number of character codes in subrange
UInt16 glyphIndexArray[entryCount] //Array of glyph index values for character
//codes in the range
子表中的 firstCode 和 entryCount 值指定可能的字符代码范围内的有用子范围。范围以firstCode开始,
长度等于entryCount。这个子范围之外的代码被认为是缺失的,并被映射到索引为 0的字形。对于子范围
内的代码,它与子范围内的 firstCode 的偏移量用作 glyphIndexArray 中的索引。该数组提供与该字符
代码关联的字形索引。
ForMat 4
格式4是一种双字节编码格式。当字体的字符代码落在几个连续的范围内时(可能部分或所有范围内都有漏
洞),应该使用它。也就是说,范围内的一些代码可能与字体中的字形无关。密集映射的双字节字体应该
使用Format 6.表格以格式、编号、长度和语言开始。与格式相关的数据如下。它分为三个部分:一个四字
标题,给出优化搜索段列表所需的参数描述段的四个并行数组(每个连续范围的代码对应一个段)一个可变
长度的字形数组.
UInt16 format // 4 Format number is set to 4
UInt16 length // 该格式下总的字节数
//Length of subtable in bytes
UInt16 language // 编码语言 Language code (see above)
UInt16 segCountX2 // 2 * segCount
UInt16 searchRange // 2 * (2**FLOOR(log2(segCount)))
UInt16 entrySelector // log2(searchRange/2)
UInt16 rangeShift // (2 * segCount) - searchRange
UInt16 endCode[segCount] // Ending character code for each
//segment, last = 0xFFFF.
UInt16 reservedPad // This value should be zero
UInt16 startCode[segCount] // Starting character code for each segment
UInt16 idDelta[segCount] // Delta for all character codes in segment
UInt16 idRangeOffset[segCount] // Offset in bytes to glyph indexArray, or 0
UInt16 glyphIndexArray[variable] // Glyph index array
段的数量由变量segCount指定。Format 4表中没有显式地使用这个变量,但是所有表参数都是从这个变量中
派生出来的。segCount 是字体中连续代码范围的数目。searchRange 值是小于或等于 segCount 的 2 的最
大幂的两倍.
每个段由startCode、endCode、idDelta和idRangeOffset进行描述。这些用于映射段中的字符代码。段按递
增的 endCode值排序。
要使用这些数组,需要搜索第一个大于或等于要映射的字符代码的 endCode。如果对应的startCode小于或
等于字符代码,则使用对应的idDelta和idRangeOffset将字符代码映射到glyph索引。否则,将返回一个未
定义的字符符号。为了确保搜索会终止,最终的endCode值必须是0xFFFF。这个段不需要包含任何有效的映
射。它可以简单地将单个字符代码0xFFFF映射到缺失的字符符号glyph 0
如果段的 idRangeOffset 值不为0,则字符代码的映射依赖于 glyphIndexArray。startCode中的字符代码
偏移量加上到idRangeOffset 值,此和用作 idRangeOffset自身内的当前位置的偏移量,以索引出正确的
glyphIdArray值。这种索引方法是有效的,因为glyphIdArray可以立即执行
字形索引的地址由下式给出:
glyphIndexAddress = idRangeOffset[i] + 2 * (c - startCode[i]) + (Ptr) &idRangeOffset[i]
在这个等式中,需要乘以2才能将值转换为字节或者,也可以使用以下表达式:
glyphIndex = *( &idRangeOffset[i] + idRangeOffset[i] / 2 + (c - startCode[i]) )
这种形式依赖于idRangeOffset是UInt16的数组。
完成字形索引操作后,将检查指定地址处的字形ID。如果它不是0(也就是说,如果它不是缺失的字形),
则将该值添加到idDelta[i]以获得实际的字形ID。
如果idRangeOffset为0,则将idDelta值直接添加到字符代码中,得到对应的glyph指数:
glyphIndex = idDelta[i] + c
所有的idDelta[i]运算都是模65536。
下表给出了将字符10-20、30-90和100-153映射到一个连续的字形索引范围所需的参数示例,本例中的参数
segCount = 4。该表给出了格式4子表示例的映射变量参数值。示例数据演示了如何计算字符-字形索引映射
值。这个表格的假设是segCountX2是8,searchRange是8,entrySelector是2,rangeShift是0。
Name Segment1 Chars10-20 Segment2 Chars30-90 Segment3 Chars100-153 Segment4 MissingGlyph
endCode 20 90 153 0xFFFF
startCode 10 30 100 0xFFFF
idDelta -9 -18 -27 1
idRangeOffset 0 0 0 0
该表执行以下映射:
10 is mapped to 10-9 or 1
20 is mapped to 20-9 or 11
30 is mapped to 30-18 or 12
90 is mapped to 90-18 or 72