ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

PDF解析

2020-12-09 12:32:48  阅读:374  来源: 互联网

标签:文件 对象 字体 00000 内容 PDF 解析


前段时间因为工作的原因,接触到了PDF文件解析以及打印,当时是被虐待了,这不被虐待了的想办法报仇不是,最近因工作比较清闲,抽空研究了几天PDF文件格式以及WIN打印(打印下一篇单独写),看似一个简单格式的PDF文件,个人感觉格式设计的还是相当复杂,涉及多方面的基础内容,比如分辨率、压缩算法、字体、多媒体内嵌等内容。简单说明下今天只简单介绍PDF格式以及通过CODE读取和写入PDF内容,不涉及WIN文件系统,这部分太复杂,涉及到软硬件、文件过滤驱动等。 PDF文件由ADOBE公司设计研发的便携式文档,支持跨平台、字体、多媒体嵌入、加密、执行脚本等特点。概念性的东西就简单介绍就到这吧,接下来简单介绍一下学习PDF 文件相关的一些资源。1.PDF格式权威指南https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/pdf_reference_1-7.pdf,ADOBE官方的,呵呵全英文的,有翻译版本但是缺少前面4章,个人觉得这也是目前学习PDF最好的学习资料,非常详细,也是你写代码解析PDF格式的权威指导者。2.开源解析库PDFSHARP、ITEXTSHARP。PDFSHARP几年前就没更新了(不推介),GITHUB地址:https://github.com/empira/PDFsharp,需要的朋友自行下载瞅瞅。比起PDFSHARP来说ITEXTSHARP这个库目前更受欢迎,在GITHUB上有1.1kstart,并且还在维护,支持.NETCORE及.NETSTANDARD标准库规范,GITHUB下载地址https://github.com/itext/itextsharp,说实话这两库我都没怎么看过,因为看起来比较费力,资料就是这些吧,个人建议最好先把PDF格式规范看个大概,起码主要的格式要了解,然后自己写代码尝试读取和写入,说白了就是一堆字节流操作,闲聊就到这,下面看实操。   对象集合初始化,PDF详细格式我就不说了啊,说实话我了解的也不多,这种细活需要时间和精力去研究。整个实操分两部分吧,读取PDF和写入PDF,我们先从读取开始吧,我这边整个用的是控制台程序,代码就不贴了,处理字节流的代码没啥可读性,主要是处理思路,我先用acrobatprodc工具创建一份简单的不能再简单的PDF文件,看图   就一个汉字,现在我们通过FileStram结合二进制流读取器读取里面的内容,看内容
"%PDF-1.7\n1 0 obj\n<</Type/Catalog/Pages 2 0 R>>\nendobj\n2 0 obj\n<</Type/Pages/Kids[4 0 R]/Count 1>>\nendobj\n7 0 obj\n<<
/Filter/FlateDecode/Length 219>>\nstream\nx�]��j�0\f��y\n\u001d�Cq���`(\u001d�\u001c���}\0�R�a���\u001c��s�$�\t,\u0010��
\u0013��n�K�.��\u0014ok��:F���b\t\u001a�\u001c\u0017�g@g�2�n{\u0013\n��z\u001a\"�\u0015��,�W��(����\u0010$q���q���
\u001eC���8�Qk�6mx3���2q�0�.N���p�\u0002�S�O�!�G\u001a��$�;*�c*]���\u00051��\u0017�i��g����bfVu��ϭ���\")U�@�3
\aqLۑ�\u000f3��\u000f}�p�\nendstream\nendobj\n10 0 obj\n<</Length1 4960/Filter/FlateDecode/Length ................................ndstream
\nendobj\n9 0 obj\n<</Type/FontDescriptor/FontName/PFWAAB+�o��,Bold/Flags 32/ItalicAngle 0/FontWeight 700/Leading 0/Ascent 1058.105\n
/Descent -261.7188/XHeight 540.0391/AvgWidth 584.9609/CapHeight 756.3477/StemV 160/MaxWidth 1000/FontBBox[12.6953125 -136.23046875
985.3515625 821.77734375]\n/FontFile2 10 0 R>>\nendobj\n11 0 obj\n[3[1000]]\nendobj\n6 0 obj\n<</Type/Font/Subtype/Type0/BaseFont
/PFWAAB+�o��,Bold/Encoding/Identity-H/ToUnicode 7 0 R/DescendantFonts[8 0 R]>>\nendobj\n4 0 obj\n<</Type/Page/Parent 2 0 R
/MediaBox[0 0 595.2756 841.8898]/Contents[5 0 R]/Resources<</ProcSet [/PDF/Text/ImageB/ImageC/ImageI]\n/Font <</F2 6 0 R>>\n>>>>\
nendobj\n5 0 obj\n<</Length 55>>\nstream\nq\nq\n0 0 0 rg\nBT\n50.25 770.577 Td\n/F2 9 Tf(\0\u0003)Tj\nET\nQ\nQ\n\nendstream\nendobj\n8 0 obj
\n<</Type/Font/Subtype/CIDFontType2/BaseFont/PFWAAB+�o��,Bold/CIDSystemInfo<</Ordering(Identity)/Registry(Adobe)\n/Supplement 0>>
\n/FontDescriptor 9 0 R/W 11 0 R>>\nendobj\nxref\n0 12\n0000000000 65535 f \n0000000009 00000 n \n0000000054 00000 n \n0000000000 00000 f
\n0000003905 00000 n \n0000004072 00000 n \n0000003776 00000 n \n0000000105 00000 n \n0000004175 00000 n \n0000003445 00000 n
\n0000000392 00000 n \n0000003750 00000 n \ntrailer\n<</Root 1 0 R/ID[<474b3c8539d96eb244f8fb3f8ed789ac><474b3c8539d96eb244f8fb3f8ed789ac>]
/Size 12>>\nstartxref\n4350\n%%EOF\n"

  里面大部分内容被我精简过了,中间部分的内容基本是被压缩过的内容,全是乱码,需要特定的算法解压。以上就是通过二进制流读取PDF文件的大概内容,几乎没有可读性可言啊,一般情况下如果不了解PDF格式,基本处于懵逼状态,有强迫症的可能还会崩溃,呵呵开个玩笑哈。上面只是给大家看个全貌啊,PDF文件解析不会这么干啊。以上那坨内容具有实际解析意义的也就是前后1024个字节,在这2048个字节里面,解析工作主要是处理最后面这1024个字节。接下来我们看看具体怎么解析(思路)。 1.首先我们需要索引到交叉引用表(startxref)的地址,后面的数值对应的也就是上一个xref的起始地址,紧跟着后面就是对象总数,这里是12个间接对象。2.接着处理文件尾trailer,获取size对象。3.把流的偏移址移动到交叉引用段xref,获取所有间接对象,过滤掉被释放的对象,f表示该对象被删除。4.获取所有间接对象的属性,从间接对象里面获取对象基地址如0000000009,表示该对象的流地址是9,族个解析。到此所有间接对象初始化已完成,后续就是通过key索引内容,在这里我们的目标很简单就是读取PDF里面的文本内容,包括x、y坐标,字体、大小、颜色等等,还原到这一步,是不是整个PDF文件都是你的菜了,看效果。   上面就是按照之前逻辑思路解析出来PDF文件的所有间接对象,上面这张图片我大概解释一下啊,Catalog根目录对象,position文件流地址索引,pages文档页面树的根结点,引用的是间接对象2 0 R,表示page这个间接对象在2号对象,简单解释就到这吧。到此我们要读取的文本内容、坐标啥的是不是啥都没看到?是的,确实如此,到这里只是把整个PDF文件的所有对象加载出来,而我们需要读取的内容、坐标等信息就包含在它们里面,并且一般情况下被压缩过。   还原文本信息,看到上面这一大坨间接对象,我们怎么找呢?1.我们索引到page这个对象,里面有个资源字典,该字典里面包含了一个间接对象6 0 R,2.接着我们索引到对象号6这个间接对象,在这个对象里面有个属性ToUnicode引用了间接对象7 0 R,3.继续索引到对象号7,是不是很繁琐啊?呵呵,接着来,不要怕繁琐,奇迹会出现的,ADOBE公司出品的必属精品,在这个对象号里面终于发现奇迹快出现了,我们通过偏移址和长度读取这部分二进制流,接着重头戏来了,FlateDecode表示该部分内容通过zlib压缩(可能会有更复杂的操作,带参数),4.通过deflate解压这部分二进制流。还有一种解析方案,直接索引Contents对象号,解析它里面的二进制流,这部分二进制流可以索引所有内容信息,或者间接引用对象,当然这部分二进制流同样需要解压,这里我贴出解析出来的contents和文本内容信息里面的内容吧BT                                                                                                                 50.25 770.577 Td                                                                                                       /F2 9 Tf // 通过字体资源索引文本内容                                                                                                
 <0003> Tj         
 
/CIDInit /ProcSet findresource begin
14 dict begin
begincmap
/CIDSystemInfo<</Registry(Adobe)/Ordering (UCS)/Supplement 0>>def
/CMapName/Adobe-Identity-UCS def
/CMapType 2 def
1 begincodespacerange
<0000><FFFF>
endcodespacerange
1 beginbfrange
<0003> <53cd> // unicode字符集,这就是我们要找的内容
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end 
                                                                             拿到以上内容,我们的文本内容属性就全部拿到了,有绘制坐标、字体、size、unicode字符集、编码等内容,到现在是不是简单的一份PDF文件,基本被我们蹂躏了?呵呵,不要急还有比较复杂的一步操作,嵌入的字体文件处理。我们知道字体ttf、ttc其实际就是一堆字符轮廓(有矢量、点、位图),通过设备绘制输出,接下来我们通过对象集合索引出字体文件,看,不要看我,看上面对象集合图,这些不是乱看的啊,通过对象引用追朔下来的啊,在8号对象里面找到属性FontDescriptor 9 0 R表示字体文件描述信息在9号对象里面,继续索引9号对象,最终守得云开见月明,找到属性FontFile2 10 0 R表示trueType字体信息在10号对象,看内容。  
............cvt XMTñ.......´fpgm,.·,...P..
.glyfà.3ë..
X...¨head
b¬¥.......6hhea.u.....8...$hmtx.[.Í...\....loca.ý.R...l...
maxp.O.....x... prep.Kî:.......Å.c.....
  删了很多信息啊,在里面是不是发现了head hmtx字样,这就是字体文件ttf、ttc字体文件结构,透露一下啊,如果我们自己实现PDF编辑工具,字体嵌入的实现,其实际就是创建这么一个ttf、ttc字体文件。看到上面这些东西,朋友们不要心急啊,这玩意还用不了啊,因为这部分内容信息同样压缩了,需要解压。我们现在还缺少一个步骤,通过字体绘制到显示器,到这里就比较简单了啊,拿到字体文件信息,各平台有加载ttf、ttc的类库,直接加载,然后设置相关字体信息就完成了。题外话,整个嵌入字体文件,如果基于代码实现还是比较复杂的啊,需要非常熟悉trueType、openType等字体结构,差不多就到这吧,写入同样按上面的逻辑来,当然肯里面还有些寻字节偏移址细节,需要自己多注意,写的不对请留言指出谢谢。

标签:文件,对象,字体,00000,内容,PDF,解析
来源: https://www.cnblogs.com/adair-blog/p/14107894.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有