我几年前也经历了这场噩梦,现在我对这些东西非常了解。我想提供一些帮助。
1) 你不能假设“loca”跟随“cmap”。顺序可能因字体而异。每个块的位置由OffsetTable定义,该表通常从字体文件的第0字节开始。(http://www.microsoft.com/typography/otspec/otff.htm)
2) 不能假设“cmap header encoding id is 0, at least in TTF format 4”表示符号字体。我确信某些旧的阿拉伯字体也使用该编码。到目前为止,我仍然不知道如何区分它们。Windows可以做到这一点,但我不知道如何做到。我不知道如何确定一个字体是否是符号字体。即使检查代码页位32的OS/2表,在许多情况下也不足够。
3) 你不能简单地使用神奇的0xF000数字并将其加到你的小型0-255数字上,以获得你要进行的字形映射的字符。那是因为这些小的0到255的“ASCII”代码将根据你的系统区域设置而变化。
符号字体在Windows处理中是特殊的。
与普通字体不同,符号字体的映射在于系统默认代码页(非Unicode应用程序,即CP_ACP)。
例如,假设你的符号字体有这个字形:'%'。如果你的系统默认使用CP 1252,则要呈现此字形,例如,你必须呈现字符值'0xC2'。
如果你的系统默认使用CP 1251,则要呈现此字形,例如,你必须呈现字符值“0x416”,这是完全不同的。
换句话说,字体的Unicode范围因默认的非Unicode代码页而异!
经过调查,我们发现字体的有效字符值是通过将0到255转换为它们的CP_ACP值而获得的unicode值。
这是什么意思?这意味着你需要使用MultiByteToWideChar和CP_ACP来获取值0到255的映射,以根据你的系统区域设置(CP_ACP)获得它们的本地化Unicode值。
所以,这样做会给你一个像这样的映射:
ASCII -> localized non-static UNICODE
0x00 -> 0x00
0x01 -> 0x01
0x02 -> 0x02
...
0xC2 -> 0x416 <----- This is correct : the value will be different in some cases.
...
0xE3 -> 0xE3
0xF000到0xF0FF是静态的UNICODE值:它们永远不会改变。
因此,要获取“本地化的非静态UNICODE”字形ID,您首先需要使用上面的映射来查找相应的ASCII值,然后将其加上0xF000,然后获取该值的字形ID。
当然,微软没有记录这些荒谬的内容...或者我找不到它。