一、问题描述
最近打开一个CAD文件显示问号,用看图王发现是钢筋字体,像往常一样替换tssdeng.shx字体。
二、初步测试
- 在CAD中通过
PR
命令查看对应的字体样式,之后输入ST
命令找到对应样式,替换tssdeng.shx
,操作后发现依旧显示问号,emmmm。 - 回到看图王中,确认就是钢筋符号。我们知道在CAD中,
单行文字
可以通过%%数字
的形式来输入CAD钢筋符号,所以这里我们测试在这段文本后面输入%%132
,可以发现钢筋字体确实被转换了。
PS:CAD支持直接输入Unicode编码,比如%%132
也可以用\u+0084
!
三、深入分析
- 既然肉眼看不出问题,那就复制到文本文档中,用
WinHex
一探究竟吧。 - 这里发现我们正常显示的Ⅲ级钢筋字体是
C2 84
,而显示异常的是EE 94 B2
,这里我们就需要查看tssdeng.shx
字体了,看看是不是缺少某些字库导致的。 - 在CAD中的SHX是矢量字库字体,平常字体编辑器无法预览,这里可以用
ShxViewer
、SHX2SHP
两款软件进行查看。 - 细心的会发现,我们在CAD输入的
%%132
中的132
转换十六进制就等于84
,所以我们在这两款软件中找到84
的位置都可以看到钢筋符号,同理我们也知道了相邻位置的钢筋符号:
16进制 | 10进制 | 解释 |
---|---|---|
\u+0082 | %%130 | Ⅰ级钢筋 |
\u+0083 | %%131 | Ⅱ级钢筋 |
\u+0084 | %%132 | Ⅲ级钢筋 |
\u+0085 | %%133 | Ⅳ级钢筋 |
... |
- 但是我们在
WinHex
中,显示C2 84
,而不是84
,为什么会多一个C2
呢?EE 94 B2
又如何计算它在字体中所对应的位置呢? - 带着这些疑问我们首先需要了解UTF-8 编码规则:
U+0000 到 U+007F(1字节):
这个范围的字符只需要一个字节,直接与 ASCII 码相同,从 `0x00` 到 `0x7F`。
U+0080 到 U+07FF(2字节):
这个范围的字符需要两个字节来编码。
第一个字节从 `110xxxxx` 开始,第二个字节从 `10xxxxxx` 开始。
这里的 `x` 代表原始Unicode代码点的比特。
U+0800 到 U+FFFF(3字节):
这个范围的字符需要三个字节来编码。
第一个字节从 `1110xxxx` 开始,随后两个字节都从 `10xxxxxx` 开始。
U+10000 到 U+10FFFF(4字节):
这个范围的字符需要四个字节来编码。
第一个字节从 `11110xxx` 开始,随后三个字节都从 `10xxxxxx` 开始。
- 这里说一下我的理解,有误请指出,首先是正向思维:
`U+0084`属于`U+0080 到 U+07FF`区间,所以最后应该得到两个字节;
`84`转换二进制得到`1000 0100`;
根据字节高低位,我们可以先算第二个字节,第二个字节从 `10xxxxxx` 开始,取`1000 0100`后六位`00 0100`与 `10xxxxxx` 拼接得到`1000 0100`,转换十六进制得到`84`;
第一个字节从 `110xxxxx` 开始,因为刚刚`1000 0100`用掉了6位,我们还剩下2位,即`10`,拼接得到`110xxx10`,但是这里我们需要5位,所以补零占位,得到`1100 0010`,转换十六进制得到`C2`;
将两个字节拼接得到`C2 84`两个字节。
- 接下来是逆向思维:
`C2 84`是两个字节,遵循UTF-8 编码规则,即第一个字节从 `110xxxxx` 开始,第二个字节从 `10xxxxxx` 开始;
`C2`转换二进制`1100 0010`取后5位得到`0 0010`;
`84`转换二进制`1000 0100`取后6位得到`00 0100`;
将两个二进制拼接得到`0 0010 00 0100`,去掉前面多余的0整理后`1000 0100`,转换十六进制得到`84`。
- 最后让我们计算EE 94 B2:
`EE 94 B2`是三个字节,遵循UTF-8 编码规则,即第一个字节从 `1110xxxx` 开始,随后两个字节都从 `10xxxxxx` 开始;
`EE`转换二进制`1110 1110`取后4位得到`1110`;
`94`转换二进制`1001 0100`取后6位得到`01 0100`;
`B2`转换二进制`1011 0010`取后6位得到`11 0010`;
将三个二进制拼接得到`1110 01 0100 11 0010`整理后`1110 0101 0011 0010`,转换十六进制得到`E532`。
- 使用上述两款软件也验证了
E532
位置不存在对应的字形。既然没有,那咱就手动添加一个试试。 - 因SHX文件不能直接修改,需要反编译成SHP文件才能修改,碰巧这两款软件都支持反编译SHP。
- 将得到的SHP文件用记事本打开,我们可以搜索找到
*132
(84)开头到下一个*
开头中间内容就是*132
的字形内容,我们把它复制到文件末尾,修改开头为*58674
(E532),然后保存。
- 回到CAD中输入
COMPILE
命令,找到更改后的tssdeng.shp
文件,选择打开
,将自动编译成tssdeng.shx
文件。关闭CAD,将新的tssdeng.shx
文件替换到CAD的fonts文件夹中,再次启动CAD,问题得到解决。其他钢筋符号或者生僻字同理。
- 当然,新的
tssdeng.shx
字体文件我们放在SHX2SHP
中也能找到E532
位置的字形了。
四、后记
- 在使用
SHX2SHP
时,如果字形存在引用的情况下,比如2,
开头是字形,7,*xx
开头是引用*xx
字形。在使用Code view
显示的不是引用的字形; - 在使用
ShxViewer
时,反编译shp文件头部会加入编译信息会导致COMPILE
命令报错,需要删除;同时*
引用的位置有时显示10进制有的显示16进制,貌似超过ff就会显示16进制?而且软件显示的数量貌似也有限制,但在SHX2SHP
根据位置可以单独查看。 - 所以上面两个软件配合着来吧。
- 其实研究到中途时,偶然发现网络上有新一版的
tssdeng.shx
文件,内部已经包含了本次E532
的字形,所以这里留一下研究思路吧,方便后面手动添加字形,也可以解决生僻字的问题,比如这篇文章:制作一个含生僻字的矢量字体文件-CSDN博客