如何从Unicode获取字体文件中的映射关系

AllCHN 2018-06-17 06:11:04
对于给定的系统字库(可以通过注册表获取对应的文件名称),给定一个系统字库名和一个Unicode代码(包括4字节CJK-B/C/D/E/F区的汉字),需要解决:
1. 字库是否存在;
2. 该字库存在的风格(Bold, Italic等等);
3. 该字符在字库文件中是否存在(Regular或Reguaular不存在则Bold,其中一种即可);
4. 字符存在时字形(Glyph)数据是否存在(非空白);
5. 字形存在时获取该字形对应的所有Unicode编码(一个字形可以对应多个Unicode编码)。

前面4项目前是可以通过API做到的,最后一项找不到头绪,请大侠帮忙,可以有偿获取源码(请加QQ商议),但需要将上面所有内容封装到一个VB类,如能同时提供VB.NET(2005或2008)可用则更好。

QQ: 616139, 请备注。
...全文
2574 31 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
31 条回复
切换为时间正序
请发表友善的回复…
发表回复
PctGL 2018-07-10
  • 打赏
  • 举报
回复
引用 楼主 AllCHN 的回复:
对于给定的系统字库(可以通过注册表获取对应的文件名称),给定一个系统字库名和一个Unicode代码(包括4字节CJK-B/C/D/E/F区的汉字),需要解决:
1. 字库是否存在;
2. 该字库存在的风格(Bold, Italic等等);
3. 该字符在字库文件中是否存在(Regular或Reguaular不存在则Bold,其中一种即可);
4. 字符存在时字形(Glyph)数据是否存在(非空白);
5. 字形存在时获取该字形对应的所有Unicode编码(一个字形可以对应多个Unicode编码)。

前面4项目前是可以通过API做到的,最后一项找不到头绪,请大侠帮忙,可以有偿获取源码(请加QQ商议),但需要将上面所有内容封装到一个VB类,如能同时提供VB.NET(2005或2008)可用则更好。

QQ: 616139, 请备注。


一会字库、一会字形。。。没明白啥意思。。。
字库,字体文件?
字形,字体文件中对应的字符?
unicode编码会根据字体不同而改变?
脆皮大雪糕 2018-07-01
  • 打赏
  • 举报
回复
可以先尝试做做双字节的,但是 1、不保证成功 2、不保证时间 3、我做私活价格不低
有兴趣私聊 QQ:71429660
脆皮大雪糕 2018-07-01
  • 打赏
  • 举报
回复
引用 28 楼 AllCHN 的回复:
有没有兴趣把这个模块做出来呀,你那么熟,可以省很多事。至于平台ID的问题,大概是4种,Windows 和 Unicode 各两种,一个只支持双字节,一个支持4字节,主要是要解决4字节编码到双字编码的映射关系


不熟啊,这也是第一次撸字体文件的文档。4字节怎么对应我也不知道啊,也要再去找其他文档
AllCHN 2018-07-01
  • 打赏
  • 举报
回复
引用 27 楼 chewinggum 的回复:
[quote=引用 26 楼 Chen8013 的回复:]
[quote=引用 24 楼 chewinggum 的回复:]
CMAP的中文版见:
http://www.bubfun.com/post/2018/06/30/ttfe69687e4bbb6e4b8adCMAPe8a1a8e7bb93e69e84.aspx


你这是“赶在时代的前列”啊…… 
[/quote]

哦,没调整博客的时区[/quote]有没有兴趣把这个模块做出来呀,你那么熟,可以省很多事。至于平台ID的问题,大概是4种,Windows 和 Unicode 各两种,一个只支持双字节,一个支持4字节,主要是要解决4字节编码到双字编码的映射关系
脆皮大雪糕 2018-06-30
  • 打赏
  • 举报
回复
引用 26 楼 Chen8013 的回复:
[quote=引用 24 楼 chewinggum 的回复:]
CMAP的中文版见:
http://www.bubfun.com/post/2018/06/30/ttfe69687e4bbb6e4b8adCMAPe8a1a8e7bb93e69e84.aspx


你这是“赶在时代的前列”啊…… 
[/quote]

哦,没调整博客的时区
舉杯邀明月 2018-06-29
  • 打赏
  • 举报
回复
引用 24 楼 chewinggum 的回复:
CMAP的中文版见:
http://www.bubfun.com/post/2018/06/30/ttfe69687e4bbb6e4b8adCMAPe8a1a8e7bb93e69e84.aspx


你这是“赶在时代的前列”啊…… 
脆皮大雪糕 2018-06-29
  • 打赏
  • 举报
回复
哎,觉得东西在大脑里面已经接近完整了,但是缺乏一个验证,但验证就要写代码,想想写代码就要把前面撸的文字再换成代码,都有点不想折腾了。而且,目前只看了format4 ,如果遇到其他的format又要重新来了
脆皮大雪糕 2018-06-29
  • 打赏
  • 举报
回复
CMAP的中文版见:
http://www.bubfun.com/post/2018/06/30/ttfe69687e4bbb6e4b8adCMAPe8a1a8e7bb93e69e84.aspx
舉杯邀明月 2018-06-29
  • 打赏
  • 举报
回复
楼上高手,分析得不错嘛。



晚上有空再继续…………
脆皮大雪糕 2018-06-29
  • 打赏
  • 举报
回复
第五点,基本上是没有现成API可以给你用的了,所以个人觉得只能直接从ttf文件着手分析,在8楼我就说了我的初步想法是利用CMAP去找重复字模。楼主发出来ttf文件了,那么就拿这个案例尝试分析一下文件,通过文件数据的查看,看看我的想法是否可行。

先看看https://docs.microsoft.com/zh-cn/typography/opentype/spec/otff
这里面描述了文件头的一些结构

我们开UE直接看这个tff文件的数据。约定一下,接下来我们所说的涉及数据地址和文件内具体的数值一切都是16进制表达,懒得进行数值转换了,而且具体的数值在UE截图上也很容易找到。


根据ttf的数据结构定义。文件最前面是一个TableDirectory结构,12个字节。1~4是固定版本号 紧接着是两个字节,说有几个表,这里看是0A也就是说有10张表。从后面我用红框框出来的表名看的确有10个表。
其他的我们都不是很关心,直接看CMAP表的信息。也就是从 1C~2B的16个字节图中我选起来的部分。 这是一个TableEntry结构,1~4字节是表名 5~8是checksum 9~12是偏移地址,13~16是表长度。从数据看,偏移在8F9C 长度是C07A
那么我们就直奔8F9C而去



接下来我们看微软的cmap文档
https://docs.microsoft.com/zh-cn/typography/opentype/spec/cmap
先是'cmap' Header结构,4个字节,1~2是cmap版本固定为0。3~4是子表数目。这里我们看到子表数目的偏移地址再 8F9E~8F9F这里显示的是03,也就是有3个子表。
那么接下来就是3个EncodingRecord 结构,这种结构8个字节 是1~2字节为Platform ID 平台ID,3~4为平台自己的special ID 5~8为子表起始位置偏移。
序号 Platform ID Platform-specific encoding ID 偏移
1 00 03 1C
2 01 00 BE70
3 03 01 1C

接着看文档 查表,平台ID 00 为unicode 01为Macintosh我们可以不管 03是windows。 继续撸文档,windows平台强烈建议(strongly recommends)用unicode表,实际上这个字库的Platform-specific encoding ID的确也是 01 Unicode BMP。 所以我们可以看到这个字体库里 子表1 和2 偏移是一样的,都指向同一个表。
麦金托什的咱不管了,专心看unicode的这张表。它的偏移是1C,也就是十进制的28。这个偏移是相对于CMAP的起始位置的偏移,也就是从 8F9C + 1C 开始是子表数据的开始。 这个1C其实也就是 一个4字节的cmap Header结构,加上3个8字节的 EncodingRecord 总共28个字节。

接下来就比较复杂了,cmap的数据格式有7种,文档中明确:Fonts that support Unicode BMP characters on the Windows platform must have a format 4 'cmap' subtable for platform ID 3, platform-specific encoding 1.
所以我们继续往下撸文档,看format4的数据结构。



Format 4 是双字节编码。这种格式用于字体文件中的编码分布与几个连续的区域,在区域之间可能有一些保留的空白。而有一些编码可能并不会与字体中的glyph对应。2字节的压缩编码则使用format6。

表头开始是格式编号format、子表长度length及语言language。紧接着是format数据。它分为3个部分:
4 word(UInt16)的头部,指定用于加快分段表查找的参数。
4个数组,用于描述段(段是一个连续的编码范围)。
glyphID数组

所以,我们要判定是否有重复的的字模,只要看 glyphID数组里面有没有重复的数据,然后反推出其对应的unicode就行了
第一步,先取得glyphID数组,无非就是算地址偏移。format4里有endCount[segCount]、startCount[segCount]、idDelta[segCount]、idRangeOffset[segCount] 这4个数组,这4个数组的尺寸其实就都是segCountX2这个字段的值(每个数组有segCount个元素,每个元素是一个uint16也就是2个字节,所以每个数组的尺寸就是segCount * 2个字节)。

好,刚才我们已经算出,cmap第一张图子表的起始地址是8F9C + 1C = 8FB8。先看一下这里开始的1~2字节,数值为04 , 文档显示format4的前两个字节固定值为4,说明到目前为止看上去还没有数错。 我们要的segCountX2在 7~8字节 值为 2406 数一下format4的结构,在glyphID数组前,一共有8个uint16字段和刚才说的4个数组。所以这些信息一共有 2*8+4*2406 = 9028 (这些全是16进制计算哈) 那么 glyphID数组的起始位置就是 8FB8 + 9028 = 11FE0

到这个地址看看数据情况:

很明显,这个地址的前后数据结构明显不同,说明咱基本没算错。然后就是取出整个数组,然后找出数组的重复项。这块就要代码实现,看UE截图没用了。至于这个数组的结尾在哪里,对于这个字库文件,可以投机取巧,因为就两个表,麦金托什表的起始位置是 8F9C + BE70 ,那么这个地址的前一个字节就是glyphID数组的结尾。算出来glyphID数组的长度应该是2E2B 。如果是最后一个表,应该要按 TableEntry结构里的对CMAP表长度的描述进行计算。

如果找到重复的glyphID,说明你找到了重复的字模了,那么接下来就是根据format4的信息反推UNICODE了
先要了解正推的算法,具体的算法可以看文档中format4结构下面的那一大段。
写到这里戛然而止,一是下班时间到了,二是正推算法我也还没看明白。待看明白以后再来吧。
AllCHN 2018-06-28
  • 打赏
  • 举报
回复
引用 20 楼 chewinggum 的回复:
为了不产生无意义的抬杠,发一个有多个unicode对应一个字模的字库案例出来呗。


http://www.keshou.top/downloads/jdfmk.ttf

这个字库是一个繁体字库,为了使输入简体字不会产生缺失(通常显示框),因此将简体和繁体做了部分映射(尽量无歧义的汉字),所以,比如“万(4E07)”和“萬(842C)”就是同一个字形的映射,很显然,也不是所谓字形识别的问题,这样的字形修改之后,两个Unicode内码对应的字形都变了。
当然,获取一个字形对应的Unicode的用途不是这么小范围,比如,对于4字节汉字(CJK-B/C/D/E/F)而言,要映射到很多应用程序可以使用的双字节,通常要靠造字(不要跟我讨论修改字体来显示的问题,事实上目前的控件绝大部分不支持双字体或者备用字体模式),只是不是要造一个字形,只是要从专用区给一个编码,这样,标准4字节到底对应哪个双字节编码,通过字库来查找对照关系显然比使用一个对照表要简单,也有更好的使用体验。
脆皮大雪糕 2018-06-28
  • 打赏
  • 举报
回复
为了不产生无意义的抬杠,发一个有多个unicode对应一个字模的字库案例出来呗。
舉杯邀明月 2018-06-27
  • 打赏
  • 举报
回复
这次改版之后,文字“加粗”了,反正我在浏览器中看到的“字”()和“宇”()是一样的。


赵4老师 2018-06-27
  • 打赏
  • 举报
回复
5. 字形存在时获取该字形对应的所有Unicode编码(一个字形可以对应多个Unicode编码)。
其中“该字形”
既可以理解为字体文件中某个唯一确定的字形数据的起始地址;
也可以理解为所有和该字形的几何形状没区别的字形。
赵4老师 2018-06-27
  • 打赏
  • 举报
回复
说风凉话凑热闹是我的专长。
AllCHN 2018-06-26
  • 打赏
  • 举报
回复
唉!谢谢你们的关心!
首先,我不是为了要学习这种技术,而是想在一个项目中解决这个问题,以前不是特别了解,不太可能花很多时间来做研究;其次,这个问题的提出只是为了使程序看起来更友好一点,稍微给使用者省点事,其实,对字库有研究的人做一个这样的模块比我肯定要省事很多,所以我也愿意给付一定的报酬;其三,一开始我觉得就描述清楚了,主要是第五条。
脆皮大雪糕 2018-06-23
  • 打赏
  • 举报
回复
引用 13 楼 Chen8013 的回复:
赵4 现在可以发言了?

又开始乱说了…………


才消停两天,带着一堆人的群嘲居然能申诉回来
舉杯邀明月 2018-06-23
  • 打赏
  • 举报
回复
赵4 现在可以发言了?

又开始乱说了…………
赵4老师 2018-06-23
  • 打赏
  • 举报
回复
用户、甲方、雇主说看上去一样就是一样;
码农、乙方、雇员说看上去一样不一定是一样,显然没用。

加载更多回复(10)

1,488

社区成员

发帖
与我相关
我的任务
社区描述
VB API
社区管理员
  • API
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧