在进行应用系统维护的过程中,因需要不同行业间交互数据,在系统和提供商纷杂的情况下,难免会出现信息处理方式不对称的尴尬。最近遇到一个比较具体的自定义冷僻字的字形问题,现处理的差不多的情况下,也该总结一下做个备忘,这里就流水账的方式记录一下解决和测试的方法。

首先需要面对的是五花八门的中文字符编码,这里就引出几个国标文件,不一定都需要理解,大概看一下有个概念就可以了。

GB 2312-1980 信息交换用汉字编码字符集 基本集
GB 13000-2010 信息技术 通用多八位编码字符集(UCS)
GB 18030-2005 信息技术 中文编码字符集
GB13000.1字符集汉字部首归部规范
GBT 11383-1989 信息处理 信息交换用八位代码结构和编码规则

接下来探究的是字符的内码,在不同的编码方案中,相同字符的内码是不一样的,又或者相同的字符在同一编码方案中还会存在重复编码(确实是有的)。这里为了方便演示,就从Windows自带的宋体字形文件中,新增一个自定义的字形最终用于生成PDF文档,使用到的工具在过程中就逐一引出。

参考GB 18030-2010文档,双字节用户区都是自定义的字形,分1~3区,这一点在Windows自带的造字程序中也体现出来了。在开始菜单中搜索eudcedit.exe就可以启动造字程序。造字的结果可生成eudc文件保存在C:\Windows\Fonts目录下,也可以由注册表指定其它的位置。如下就是搜狗字库自定义字形的定义注册表,936表示的是GBK的code page。

HKEY_CURRENT_USER\EUDC\936SystemDefaultEUDCFont=C:\Users\entryman\AppData\LocalLow\SogouPY\EUDC\SGPYEUDC_1.TTE

造字程序中EUDC是end-user-defined characters的缩写,也就是终端用户定义字符,直接上图。

其中范围下拉框就可以选择用户区的1~3个分区,对应到上面提到的国标定义,图片中的汉字就是搜狗自定义的字库。字形看上去可能大家都认识,但是Unicode码的对应关系完全是看自己发挥,这也是在信息系统之间传递和显示出现差异的罪魁祸首。上图左侧的双字节编码就是Unicode的内码,系统间交互大都使用Unicode编码,虽然各自系统表示的却是不同的汉字。这里就得提提下工业标准中常用的UTF8编码方案,有一个概念需要先弄清楚,在说UCS2时指的是字符编码,表示这个字符存储和传输占用两字节的空间,而UTF8是一种对Unicode的编码,用于序列号这种表示,可以使用1~6字节来表示一个字符,首字节几个1开头,就表示共使用几个字节组合表示,这和GB 13000中描述的辅助平面的概念有些类似。下图就是UTF8编码方案表示字符的示意,x表示有效用来表示字符内容的,其余的1和0为了表示一共采用几个字节表示一个字符。可以看出UTF8最大能表示的字符码值为2的31次方,也就是十进制的2147483648,十六进制的0x80000000。

Unicode符号范围     |        UTF-8编码方式(十六进制)         |         (二进制)
----------------------+----------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

接下来开始实操,首先从Windows系统自带的字体中取出宋体字体文件,位置在C:\Windows\Fonts\simsun.ttc,为了操作上的安全,先把这个文件拷贝到一个临时目录。

copy C:\Windows\Fonts\simsun.ttc D:\Workshop\Sources\Fonts\

TTC的文件扩展名表示这个文件包含了多个TrueType字体文件,也就是TTF,接下来用工具可以看到这些信息,TTC是TureType Collection的缩写。这里引出第一个工具,Adobe Font Development Kit for OpenType (AFDKO),这家伙免费的,源代码也放在GitHub上,Adobe官网也是有介绍的,使用Python实现的功能,当前的版本依赖Python 3.6,一切从简,安装它。

pip install afdko

安装好以后开始查看simsun.ttc文件的内容,可以执行afdko命令看更多的参数开关信息,如下所示。

(base) D:\Workshop\Sources\Fonts>otc2otf -r simsun.ttc
Input font: simsun.ttcFont 0: SimSun.ttftag     checksum    length    offset----  ----------  --------  --------EBDT  0x72A25569   5528924       780EBLC  0x18CDBFEA    683648   5529704GDEF  0x7080707E        30   6213352GPOS  0x73A683B2        66   6213384GSUB  0xDC28F7E6       822   6213452MERG  0x00160001        12   6214276OS/2  0x50D18CD0        96   6214288cmap  0xBC0D63BF      1984   6214480cvt   0x04BA01CD       186   6216464fpgm  0xC564B4F6      3566   6216652gasp  0x00530031        20   6220220glyf  0x82AAE3C2  11707144   6220240head  0xF3329F66        54  17927384hhea  0x02015711        36  17927496hmtx  0x719345FD    101740  17927532loca  0x3A4A5F22    115176  18029272maxp  0x735A04D0        32  18144448meta  0x8C0585B4       102  18144480name  0x23F2727D      2028  18144584post  0xFFED000C        32  18148648prep  0x51510FE7       516  18148712vhea  0x01E100DD        36  18149228vmtx  0xE99ADF07     57592  18149264Font 1: NSimSun.ttftag     checksum    length    offset----  ----------  --------  --------EBDT  - shared -EBLC  - shared -GDEF  - shared -GPOS  - shared -GSUB  - shared -MERG  - shared -OS/2  0x53518CD9        96   6214384cmap  - shared -cvt   - shared -fpgm  - shared -gasp  - shared -glyf  - shared -head  0xF3329F67        54  17927440hhea  - shared -hmtx  - shared -loca  - shared -maxp  - shared -meta  - shared -name  0xC83DA902      2033  18146612post  0xFFED000D        32  18148680prep  - shared -vhea  - shared -vmtx  - shared -

在这里可以看出,simsun.ttc文件中包含SimSun.ttf和NSimSun.ttf两个文件,而且两者都有共享数据,这里我们把这两个文件都摘出来,可以先看看otc2otf命令支持的开关信息,比较简陋。

(base) D:\Workshop\Sources\Fonts>otc2otf -h
usage: otc2otf [-h] [--version] [-v] [-r] TTC FONTExtract all OpenType fonts from the parent OpenType Collection font.positional arguments:TTC FONT       path to TTC fontoptional arguments:-h, --help     show this help message and exit--version      show program's version number and exit-v, --verbose  verbose modeUse -vv for debug mode-r, --report   report the TTC's fonts and tables (no files are written)(base) D:\Workshop\Sources\Fonts>otc2otf -v simsun.ttc
INFO:afdko.otc2otf:Saved D:\Workshop\Sources\Fonts\SimSun.ttf
INFO:afdko.otc2otf:Saved D:\Workshop\Sources\Fonts\NSimSun.ttf

摘取到TTF文件后下一个工具就要登场,使用FontCreator打开这两个文件,查看里面的字形,并在PUA区域添加一个自定义字形,这里为了掩饰直接从其它区域拷贝一个字形,重新赋予它Unicode内码,当在应用程序中出现这个Unicode内码时,展现组件就会去寻找这个字形了。

软件操作就不赘述了,界面还是比较友好的,编辑结束后将两个TTF文件各自导出,覆盖原先摘取的文件,接着用otf2otc将这两个文件合并。

(base) D:\Workshop\Sources\Fonts>otf2otc -hotf2otc  -t <table tag=src font index> -o <output ttc file name> <input font file 0> ... <input font file n>-t <table tag=source font index>  Optional. When this option is present, the matching table from the specified font file is
used for all the font files.example:otf2otc -t 'CFF '=2 -o LogoCutStd.ttc LogoCutStd-Light.otf LogoCutStd-Medium.otf LogoCutStd-Bold.otf LogoCutStd-Ultra.otf
# The 'ttc' file will contain only one CFF table, taken from  LogoCutStd-Bold.otf.The script mbe invoked with either the FDK command:otf2otc
or directly with the command:python <path to FDK directory>/python/afdko/otf2otc.pyBuild an OpenType Collection font file from two or more OpenType font
files. The fonts are ordered in the output 'ttc' file in the same order
that the file names are listed in the command line. If a table is
identical for more than one font file, it is shared.(base) D:\Workshop\Sources\Fonts>otf2otc -o simsun.ttc SimSun.ttf NSimSun.ttf
Input fonts: ['SimSun.ttf', 'NSimSun.ttf']
Output font: simsun.ttc
Shared tables: ['EBDT', 'EBLC', 'GDEF', 'GPOS', 'GSUB', 'MERG', 'cmap', 'cvt ', 'fpgm', 'gasp', 'glyf', 'hhea', 'hmtx', 'loca', 'maxp', 'meta', 'prep', 'vhea', 'vmtx']
Un-shared tables: ['OS/2', 'head', 'name', 'post']
Done

可以看出,合并的过程中自动共享了数据。在重新生成TTC文件后,使用Apache™ FOP (Formatting Objects Processor)将我们的字体文件内嵌到PDF,来验证修改的结果。首先使用FOP工具从TTC生成字形的XML,为了简便,这里用脚本一气呵成了。

#encoding:utf-8jars = [
'D:/Applications/Java/jdk1.8.0_192/lib/tools.jar',
'D:/Applications/fop-2.5/fop/lib/batik-all-1.13.jar',
'D:/Applications/fop-2.5/fop/lib/commons-io-1.3.1.jar',
'D:/Applications/fop-2.5/fop/lib/commons-logging-1.0.4.jar',
'D:/Applications/fop-2.5/fop/lib/fontbox-2.0.16.jar',
'D:/Applications/fop-2.5/fop/lib/serializer-2.7.2.jar',
'D:/Applications/fop-2.5/fop/lib/xalan-2.7.2.jar',
'D:/Applications/fop-2.5/fop/lib/xercesImpl-2.12.0.jar',
'D:/Applications/fop-2.5/fop/lib/xml-apis-1.4.01.jar',
'D:/Applications/fop-2.5/fop/lib/xml-apis-ext-1.3.04.jar',
'D:/Applications/fop-2.5/fop/lib/xmlgraphics-commons-2.4.jar',
'D:/Applications/fop-2.5/fop/build/fop.jar'
]ttfs = [
'SimSun',
'NSimSun'
]ENV['CLASSPATH'] = jars.join(';')
ttfs.each do |ttf|IO.popen("java org.apache.fop.fonts.apps.TTFReader -ttcname #{ttf} simsun.ttc #{ttf}.xml") do |io|puts io.readend
endIO.popen("java org.apache.fop.cli.Main -c fop.cfg -fo fop.fo -pdf test.pdf") do |io|puts io.read
end

脚本执行结果显示如下。

---------- Ruby-x64 ----------
九月 06, 2020 1:57:27 上午 org.apache.fop.fonts.apps.TTFReader main
信息: TTF Reader for Apache FOP 2.5九月 06, 2020 1:57:27 上午 org.apache.fop.fonts.apps.TTFReader main
信息: Parsing font...
九月 06, 2020 1:57:27 上午 org.apache.fop.fonts.apps.TTFReader loadTTF
信息: Reading simsun.ttc...
九月 06, 2020 1:57:27 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: This is a TrueType collection file with 2 fonts
九月 06, 2020 1:57:27 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: Containing the following fonts:
九月 06, 2020 1:57:27 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: SimSun <-- selected
九月 06, 2020 1:57:27 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: NSimSun
九月 06, 2020 1:57:27 上午 org.apache.fop.fonts.apps.TTFReader loadTTF
信息: Font Family: [宋体, SimSun]
九月 06, 2020 1:57:27 上午 org.apache.fop.fonts.apps.TTFReader constructFontXML
信息: Creating xml font file...
九月 06, 2020 1:57:27 上午 org.apache.fop.fonts.apps.TTFReader main
信息: Creating CID encoded metrics...
九月 06, 2020 1:57:27 上午 org.apache.fop.fonts.apps.AbstractFontReader writeFontXML
信息: Writing xml font file SimSun.xml...
九月 06, 2020 1:57:27 上午 org.apache.fop.fonts.apps.TTFReader main
信息: This font contains no embedding license restrictions.
九月 06, 2020 1:57:27 上午 org.apache.fop.fonts.apps.TTFReader main
信息:
九月 06, 2020 1:57:27 上午 org.apache.fop.fonts.apps.TTFReader main
信息: XML font metrics file successfully created.
九月 06, 2020 1:57:28 上午 org.apache.fop.fonts.apps.TTFReader main
信息: TTF Reader for Apache FOP 2.5九月 06, 2020 1:57:28 上午 org.apache.fop.fonts.apps.TTFReader main
信息: Parsing font...
九月 06, 2020 1:57:28 上午 org.apache.fop.fonts.apps.TTFReader loadTTF
信息: Reading simsun.ttc...
九月 06, 2020 1:57:28 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: This is a TrueType collection file with 2 fonts
九月 06, 2020 1:57:28 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: Containing the following fonts:
九月 06, 2020 1:57:28 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: SimSun
九月 06, 2020 1:57:28 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: NSimSun <-- selected
九月 06, 2020 1:57:28 上午 org.apache.fop.fonts.apps.TTFReader loadTTF
信息: Font Family: [NSimSun, 新宋体]
九月 06, 2020 1:57:28 上午 org.apache.fop.fonts.apps.TTFReader constructFontXML
信息: Creating xml font file...
九月 06, 2020 1:57:28 上午 org.apache.fop.fonts.apps.TTFReader main
信息: Creating CID encoded metrics...
九月 06, 2020 1:57:28 上午 org.apache.fop.fonts.apps.AbstractFontReader writeFontXML
信息: Writing xml font file NSimSun.xml...
九月 06, 2020 1:57:29 上午 org.apache.fop.fonts.apps.TTFReader main
信息: This font contains no embedding license restrictions.
九月 06, 2020 1:57:29 上午 org.apache.fop.fonts.apps.TTFReader main
信息:
九月 06, 2020 1:57:29 上午 org.apache.fop.fonts.apps.TTFReader main
信息: XML font metrics file successfully created.
九月 06, 2020 1:57:33 上午 org.apache.fop.events.LoggingEventListener processEvent
信息: Rendered page #1.
九月 06, 2020 1:57:33 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: This is a TrueType collection file with 2 fonts
九月 06, 2020 1:57:33 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: Containing the following fonts:
九月 06, 2020 1:57:33 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: SimSun
九月 06, 2020 1:57:33 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: NSimSun <-- selected
九月 06, 2020 1:57:33 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: This is a TrueType collection file with 2 fonts
九月 06, 2020 1:57:33 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: Containing the following fonts:
九月 06, 2020 1:57:33 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: SimSun <-- selected
九月 06, 2020 1:57:33 上午 org.apache.fop.fonts.truetype.OpenFont checkTTC
信息: NSimSun

可见将字体内嵌到PDF,并最终正确生成了文档,其中FOP的配置文件如下。

<?xml version="1.0" encoding="UTF-8"?>
<fop version="1.0"><base>.</base><renderers><renderer mime="application/pdf"><filterList><value>flate</value></filterList><fonts><font metrics-url="SimSun.xml" kerning="yes" embed-url="simsun.ttc"><font-triplet name="SimSun" style="normal" weight="normal"/><font-triplet name="SimSun" style="normal" weight="bold"/><font-triplet name="SimSun" style="italic" weight="normal"/><font-triplet name="SimSun" style="italic" weight="bold"/></font><font metrics-url="NSimSun.xml" kerning="yes" embed-url="simsun.ttc"><font-triplet name="NSimSun" style="normal" weight="normal"/><font-triplet name="NSimSun" style="normal" weight="bold"/><font-triplet name="NSimSun" style="italic" weight="normal"/><font-triplet name="NSimSun" style="italic" weight="bold"/></font></fonts></renderer></renderers>
</fop>

待处理的文档如下。

<?xml version="1.0" encoding="utf-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"><fo:layout-master-set><fo:simple-page-master master-name="simple" page-height="29.7cm" page-width="21cm" margin-top="1cm" margin-bottom="2cm" margin-left="2.5cm" margin-right="2.5cm"><fo:region-body margin-top="3cm"/><fo:region-before extent="3cm"/><fo:region-after extent="1.5cm"/></fo:simple-page-master></fo:layout-master-set><fo:page-sequence master-reference="simple"><fo:flow flow-name="xsl-region-body"><fo:block font-size="18pt" font-family="SimSun" line-height="24pt" text-align="center" padding-top="3pt"> 这是宋体汉字-&#xe863;</fo:block><fo:block font-size="18pt" font-family="NSimSun" line-height="24pt" text-align="center" padding-top="3pt"> 这是新宋体汉字-&#xe863;</fo:block></fo:flow></fo:page-sequence>
</fo:root>

这里使用实体字符直接把字形中的Unicode码塞进去测试,避免了因当前系统的输入法、环境字符编码、自造字形注册等差异造成的误会和困扰,XML实体字符的表示方法为Ampersand加Sharp再加进制数最后分号结束,输出的PDF文档如下体所示。

中文自定义字符字形的处理相关推荐

  1. R语言str_flatten函数通过自定义字符连接(concatenate)字符串向量中的字符串

    R语言str_flatten函数通过自定义字符连接(concatenate)字符串向量中的字符串 目录 R语言st

  2. JavaScript表单验证,输入中文时字符长度为2

    获取输入框中的字符长度进行表单验证,当输入英文时字符长度就是1,当输入中文时字符长度为2. 字符数为4~16位, 上图: 一个中文抵两英文. 上代码 1 btn.addEventListener('c ...

  3. PIC18F452之1602自定义字符

    源:PIC18F452之1602自定义字符 转载于:https://www.cnblogs.com/LittleTiger/p/4595823.html

  4. c语言用星号输出大写字母H,如何在C语言中用星号或自定义字符打印方形图案

    如果你是学生, 则可能必须解决用某些预定义的编程语言打印带有X长度的某些字符(通常是星号)的正方形的问题.在这种情况下, 我们将向你说明如何使用C语言实现. 在控制台上打印带有字符的正方形的逻辑如下. ...

  5. hive正则表达式匹配中文或者字符

    hive正则表达式匹配中文或者字符 regexp_replace() regexp_extract() regexp_replace() 案例1: select regexp_replace('四川成 ...

  6. Lcd1602液晶 基础教程 常用指令 自定义字符

    此文章,你将会看到,或了解到 工作电压电流 引脚对应关系 基本操作时序 相关指令说明 显示一个字符 自定义字符的方法 工作电压电流 工作电流:2mA(5V) 背光Led:10-20mA 引脚对应关系 ...

  7. 基于51单片机点亮LCD1602+自定义字符

    1602有8位的数据口和4位的数据口,今天我们用到的是8位的数据口.废话不多说,直接上原理图 8位数据口一定要加上拉电阻,要不然驱动不了. 写数据和写命令的时序 清屏指令 开显示指令 显示字符的地址 ...

  8. iDeneb v1.6 安装教程(含中文自定义详细驱动说明)

    iDeneb v1.6 安装教程(含中文自定义详细驱动说明) 本系统是适合在非苹果的PC电脑上安装的,所以不要在苹果机上使用. 此教程重点在二楼: 最低配置: CPU SSE2 x86,512MB 内 ...

  9. 单片机c语言字符发送函数,求1602显示自定义字符 ℃ 的C语言程序,在写入和读函数多点说明,因为是初学者,...

    #include __CONFIG(0X1832); //芯片配置字,看门狗关,上电延时开,掉电检测关,低压编程关,加密,4M晶体HS振荡 #define rs RA1 #define rw RA2 ...

最新文章

  1. python中try except处理程序异常的三种常用方法
  2. Vue计算属性和监听属性
  3. Refactoring
  4. dbus PHP,安装dbus-python的简要教程
  5. 360能卸载oracle,如何完全卸载Oracle
  6. python 输入列表 返回每个元素出现的次数
  7. python语言发展历时_编程语言十年发展史
  8. python编程实战(三):暴力破解WIFI密码!亲测运行有效!
  9. 向日葵显示服务器连接失败,向日葵连接服务器成功远程不
  10. 光敏二极管的工作原理
  11. 《崩坏:星穹铁道》游戏遇到打不开/闪退/黑屏怎么办?
  12. python口算训练出题
  13. win10网络连接出现感叹号
  14. css3 滤镜效果(黑白滤镜、模糊化处理等)
  15. 推荐系统笔记(MAB问题)
  16. google中国android文档官网地址
  17. word设置多级混合标题(自动编号、交叉引用、题注 图1-1)
  18. 自热锅中发热包氧化钙 铝粒 碳酸氢钠的作用
  19. 【一笔画益智游戏教程攻略】总共有100关图文教程
  20. 【Linux】基础指令+学习

热门文章

  1. 利用PHP调用BizMail OpenApi(腾讯企业邮箱)进行接口开发
  2. 小钱狗狗(读后归纳)
  3. QT笔记- QGraphicsView视图- QGraphicsItem::setAcceptHoverEvents()设置开启鼠标悬停事件
  4. python虚拟环境是什么意思_Python虚拟环境详解
  5. 页面即时聊天客服功能
  6. CMCC协议开发(一)
  7. 去除在线看电影或者电视剧、综艺节目之前各种广告
  8. 基于flask的YOLO目标检测web服务及接口
  9. github使用 9个步骤
  10. 帝国网站管理系统网站迁移教程