从pdf和字体内部格式简单分析pdf复制提取文字乱码的原理

wxleasyland@139.com

2021.12

参考别人《PDF内嵌字体分析 - 提取的文字是乱码原因分析》。

一般PDF文件中都是有嵌入字体的,这样阅读器可以正常显示。

“我”的GB码是CED2,unicode是6211。

在WIN10记事本中,就打一个“我”字,再打到dopdf成一个pdf。

一、对pdf文件分析

在pdf文件中,有:

object3号对象是页,指出F1字体是6号对象。

object4号对象是显示内容,解压后:

q

q

BT

/F1 12 Tf                ---采用F1字体,即6号对象

0 0 0 rg

0.9998 0 0 1 56.64 760.8 Tm

[<1841>] TJ              -----显示字形索引值为0x1841的字符

ET

Q

Q

object6号对象是字体,类型Type0,指出DescendantFonts在7号对象,并指出“cmap对象”ToUnicode在11号对象。

object7号对象是字体,类型CIDFontType2,指出字体描述符在8号对象。

object8号对象是字体描述符,指出CIDSet在9号对象,字形在10号对象。

object9号对象是CIDSet,解压后都是00,不知道什么意思。

object10号对象是字体字形数据,可以提取出来变成ttf。

object11号对象是“cmap对象”,没压缩:

begincmap

/CIDSystemInfo

<< /Registry (Softland) /Ordering (Identity) /Supplement 0 >> def

/CMapName /Softland def

/CMapType 2 def

1 begincodespacerange

<0000> <FFFF>

endcodespacerange

1 beginbfchar

<1841> <6211>    -----这里是字形索引值和unicode的对应关系

endbfchar

endcmap

即表示字形索引值0x1841是对应unicode u+6211,这样阅读器就可以提取pdf中的文本了。

尝试:

如果我把object4号对象中的[<1841>]改成别的字符的字形索引值,则阅读器就是显示成别的字符了!

如果我把“cmap对象”中的unicode<6211>改成<6212>,则阅读器显示是“我”,但提取出来的文本变成了“戒”,即unicode u+6212了!!!

所以:

pdf是直接按字体中的字形索引值来显示字符的,而不是根据unicode去字体里找字形。

pdf是按“cmap对象”来提取字符的,如果pdf中没有“cmap对象”或“cmap对象”不正确,那阅读器无法提取文本。

二、fontforge软件来看字体文件:

glyph就是指“字形”。

提取pdf中字体的stream数据,WINHEX进行解压inflate,再加扩展名.ttf。

fontforge软件打开这个.ttf。

菜单view\go to,可以查找到某个字形。

view\lable glyph by\encoding hex ,让字形上方标签的显示方式变成字形编码数值。 有时好像没有用,必须要encoding reencode一下。

菜单encoding\reencode,是重新排序。

encoding\reencode\glyph order, 是按字形索引值进行排序。这时,显示顺序就变成是字体里字形索引值编码的顺序了,即index值。

在字形索引值编码0x1841下(对应u+6211),有“我”这个字形。

fontforge看,有0x7079=28793个字形框,即可以存28793个字形。(含index0)

三、TTF字体文件内部分析

根据别人《ttf文件结构解析》和ttf文件格式。

看.ttf文件内部:

maxp表数据中,总字形数是n=0x7079=28793个,和上面的一致。

loca表:是把索引转换为字形数据表内的偏移量。

loca表中有n+1个索引项,即总字形数+1。最后多了一个额外的索引项是为了方便计算差值,从而得到最后一个字形的数据长度。

loca表数据长度是0x1c1e8=115176, 因为loca索引数据是n+1=28794个, 即每个索引项是4个字节的ULONG型!

(索引项存的是字形数据表的偏移量,有分ULONG型和USHORT型)

loca表数据从文件OFFSET 0x1a68e=108174开始。

“我”索引值是0x1841=6209,故108174+6209*4=133010=0x20792,这个位置存的就是字形数据表的偏移量,ULONG型。

对于loca表数据:

By definition, index zero points to the “missing character,” which is the character that appears if a character is not found in the font.    The missing character is commonly represented by a blank box (such as  ) or a space.       If the font does not contain an outline for the missing character, then the first and second offsets should have the same value.     This also applies to any other character without an outline, such as the space character.   

根据定义,索引0指向“缺少的字符”,它是指存在的字符但在字体中找不到的字符。    “缺少的字符”通常由空白框或空格表示。    对于缺少的字符,如果字体不包含它的字形,则第一个偏移量和第二个偏移量应具有相同的值!!   这也适用于没有字形的任何其他字符,例如空格。   

---WXL:即如果这个索引值表示的字符是没有字形的,则它的偏移量和下一个索引值的偏移量值是一样的。   

即下一个偏移量减去当前偏移量之差=当前字符的字形数据长度,  差如果为0,则表示当前字符没有字形!!!

这样看来,偏移量都是顺着下去的,两个不同的索引不能指向同一个字形!无法这样表达。

比如另外一个字体中的loca数据,这里索引项是2字节USHORT型:

00 00   00 40     00 40    00 40 00 40 00 40 00 40 00 40

索引0   索引1    索引2

注意:这里索引0有字形,字形数据长度是(40H-00H=40H)*2。一般索引0是没有字形的吧。

索引1和索引2差值为0,故索引1没有字形。后同。

00 40 00 40 00 40 00 40 00 40 00 40 00 40 00 40

。。。。。。

00 40 00 40 00 40 00 40   00 40    00 91    00 91   00 91

                          索引68   索引69

索引68有字形,索引69没有字形。

字体中有cmap表:是把字符代码(unicode或非unicode)转换到字形索引值!

cmap表有PlatformID和EncodingID,代表是什么系统、什么编码类型。

平台ID3是代表WINDOWS系统。

PlatformID  EncodingID Description

3 0   Symbol

3 1   Unicode

3 2   ShiftJIS

3 3   Big5

3 4   PRC

unicode型的字体文件中,有字形索引值index和unicode的关系,可以自己编程查看。比如索引值0x1841对应u+6211。

非unicode型的字体文件,比如Big5型的字体文件,文件中应该是字形索引值index和BIG5的关系,没有对应unicode,就需要自己另外编程转换到unicode了。

如果字体是自定义图形,则根本就没有对应的unicode,一般就是映射到ASCII。这个没有转换的意义,用字形编码index就好了。

四、总的来说:

字体文件五花八门,所以PDF是直接采用字体文件中的字形索引值index来显示字符,是有道理的。

需要pdf里面的“cmap对象”来将的字形索引值index转成unicode,以提取文字。

反正,PDF中有嵌入字体,或系统中有字体,就一定能正常显示,不管是什么文字或符号。但能不能正常提取文字,就看有没有“cmap对象”了。

如果pdf没有“cmap对象”,可能可以考虑从字体入手,自行转换。或者OCR了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值