我试图绕过truetype规范。在this page上的' cmap'部分格式4 ,参数 idDelta 被列为无符号16位整数(UInt16)。然而,更进一步,给出了几个例子,这里给idDelta赋值-9,-18,-27和1.这怎么可能?
答案 0 :(得分:0)
该页面上idDelta
的定义和使用不一致。在struct subheader
中,它被定义为int16
,而稍早一点的同一个子标题被列为UInt16*4
。
这可能是规范中的一个错误。
如果你看一下实际的实现,like this one from perl Tk,你会发现idDelta通常是签名的:
typedef struct SUBHEADER {
USHORT firstCode; /* First valid low byte for subHeader. */
USHORT entryCount; /* Number valid low bytes for subHeader. */
SHORT idDelta; /* Constant adder to get base glyph index. */
USHORT idRangeOffset; /* Byte offset from here to appropriate
* glyphIndexArray. */
} SUBHEADER;
或者查看libpdfxx的实施:
struct SubHeader
{
USHORT firstCode;
USHORT entryCount;
SHORT idDelta;
USHORT idRangeOffset;
};
答案 1 :(得分:0)
这不是规范中的错误。对于示例,它们在idDelta
行中显示负数的原因是All idDelta[i] arithmetic is modulo 65536.
(引自上一节)。这是这样的。
获取字形索引的公式为
glyphIndex = idDelta[i] + c
其中c
是字符代码。由于此表达式必须是模数65536,因此如果您使用大于2个字节的整数,则该表达式等于以下表达式:
glyphIndex = (idDelta[i] + c) % 65536
idDelta
是u16,所以假设它的最大值为65535(0xFFFF
),则glyphIndex
等于c - 1
,因为:
0xFFFF + 2 = 0x10001
0x10001 % 0x10000 = 1
您可以将其视为发生溢出时环绕0的16个整数。
现在请记住,模是重复除法的,保留余数。好吧,在这种情况下,由于idDelta
仅16位,所以模将需要做的最大除法数量是1,因为从两个16位整数相加中可以得到的最大值是0x1FFFE
,小于0x100000
。这意味着快捷方式是减去65536(0x10000
)而不是执行模。
glyphIndex = (idDelta[i] - 0x10000) + c
这就是示例在表中显示的值。这是我解码的.ttf文件的一个实际示例:
我想要字符代码97(小写的“ a”)的索引。
idDelta[2] == 65507
glyphIndex = (65507 + 97) % 65536 === 68
与(65507 - 65536) + 97 === 68