问题描述
在 TrueType 字体的 cmap 格式 4 中,段的 idDelta 和 idRangeOffset 是否可能都非零?如果是这样,为什么?
如果从 glyphIndexArray 中提取的字形索引可以是字体制造商想要的任何东西,为什么还需要添加 idDelta?
解决方法
根据 https://docs.microsoft.com/en-us/typography/opentype/otspec140/cmap#format-4-segment-mapping-to-delta-values,这是没有意义的,因为非零的 idRangeOffset
意味着解析器需要查询 glyphIdArray
,它不涉及 {{1 }} 值,而 idDelta
表示段的字形 ID 基于将 idRangeOffset:0
添加到字符代码偏移量,并且不使用 {{ 1}}。
所以要回答您的问题:“如果从 glyphIndexArray 中提取的字形索引可以是字体制造商想要的任何东西,为什么还需要添加 idDelta?”,原因是“因为根本不会发生这种情况”。
引用规范:
如果段的 idRangeOffset 值不为 0,则字符代码的映射依赖于 glyphIdArray。与 startCode 的字符代码偏移量被添加到 idRangeOffset 值中。该总和用作 idRangeOffset 自身内当前位置的偏移量,以索引出正确的 glyphIdArray 值。这个模糊的索引技巧有效,因为 glyphIdArray 紧跟在字体文件中的 idRangeOffset 之后。产生字形索引的 C 表达式是:
*(idRangeOffset[i]/2 + (c - startCount[i]) + &idRangeOffset[i])
值 c 是有问题的字符代码,i 是 c 出现的段索引。如果索引操作得到的值不为0(表示missingGlyph),则将idDelta[i]加入其中,得到字形索引。 idDelta 算法是模 65536。
如果 idRangeOffset 为 0,则直接将 idDelta 值添加到字符代码偏移量(即 idDelta[i] + c)中,得到对应的字形索引。同样,idDelta 算法是模 65536。
虽然规范假设你知道 C 是如何工作的,但现在人们并不知道:前面的 idDelta
意味着我们正在计算一个字节偏移量,相对于文件的开头。 glyphIdArray
表示“这个东西的内存位置”(尽管在这种情况下,这意味着我们字体文件中的字节偏移量),因此我们将一个数字(*
)添加到ith 范围偏移量 (&
),它为我们提供了一个新的偏移量。如果我们从与该数字对应的字节偏移量开始读取字体字节,我们将在正确的位置读取我们的字形 ID。