⼀个简单PDF⽂件的结构分析
⼀个简单的PDF⽂件结构的分析
Adobe的PDF参考告诉我们⼀个PDF⽂件可以通过下⾯4个⽅⾯来理解:
1.        对象, ⼀个PDF⽂档是由⼀组基本数据类型组成的数据结构。
2.        ⽂件(物理结构), 决定对象是如何存放在⼀个PDF⽂件中的, 它们是如何被访问的,如何被更新的。这个结构是独⽴于对象的语义的。
3.        ⽂档结构, 说明⼀些基本的对象类型是如何来表现PDF⽂档的成分的:例如页,图⽚,字体,批注等。
4.        内容流,⼀个PDF⽂件内容流包含⼀系列的指令,描述页⾯的外观或其他图形实体的外观和⽂件内容。
但是当时对我来说要看懂这⼏⾏字是有很⼤的困难的,需要了解确切含义,必须看完后⾯的⼏⼗页上百页的内容并且要分析⼀个实际的PDF⽂件才能完全领会它的意思。
后来经过长时间的⽂档阅读,相关开发,并且具体地分析PDF⽂件后才把PDF⽂件的语法,⽂件的解析搞清楚。虽然说学习是痛并快乐着,但是对于当时的我来说真得希望有⼀个⼈能够告诉我⼀个简单的例⼦,通过⼀个简单的例⼦来描述PDF的基本组成,它的解析原理和过程。从我的切⾝体验来说,从⼀个初学者的⾓度出发,最好的⽅式应该是⼀个简单的例⼦。因此我主要将以⼀个简单的例⼦并且加以图例来说明PDF的主要特性并给出⼀个简单的PDF⽂件的全景。
在继续阅读该⽂章前,先问⾃⼰下⾯的两个问题:
1. 你了解⾄少⼀种⽂件格式吗?(例如HTML)
2. 为什么要学习PDF的相关知识?爱田奈奈
如果你对第⼀个问题的答案为“是”, 并且第⼆个问题你能给出⼀个⾮常明确的答案,那么这篇短⽂就是为你准备的。否则,如果对任何⼀种格式都不了解,建议你先了解⼀下HTML,或XML,你可以从这两种语⾔⾥得到很多启发,对学习PDF的构成或研究学习其他格式⽂件有很⼤的好处;如果你不清楚你要学习是为了什么,那么我就认为你学习没有⽬的性和动⼒,说不定你今天学了以后明天就忘得⼀⼲⼆净,因此也不建议你继续看下去,等到你想清楚了欢迎你来看这则短⽂。
1.PDF格式和HTML,XML格式:
马尔福
⼀个PDF⽂档从根本上来说是⼀个8字节序列。 其实PDF格式和我们已经熟知的HTML,XML等结构化的⽂件格式⼀样,包含有关键字,分隔符,数据等等。
不同的是PDF⽂件是按照⼆进制流的⽅式保存的,⽽html⽂件则是可读的⽂本⽅式保存的,你可以⽤⽂本编辑器分别打开⼀个html⽂件和PDF⽂件⽐较⼀下就知道了。XML⽂件⼀般只包含数据本⾝,并没有把如何显⽰的信息放在其中,因此要显⽰⼀个XML⽂件还需要⼀个Schema⽂件才能显⽰,否则看到的将是所有的字节流,包括所有的标志;HTML包含了数据的同时也包含了⼀些关于如何显⽰的信息,但是HTML是按照是不经过压缩的⽂本存放的,是可读的,你打开⼀个HTML⽂件就能知道所有将显⽰在浏览器⾥的⽂字。 另外就是HTML 不能包含⼆进制流,它对图像⽂件的引⽤都是通过引⽤外部⽂件的⽅式来实现的。
2.PDF规范的发展
PDF规范从1993年到现在,已经有过7个版本,六次版本升级,从最初的pdf1.0版本到现在的PDF1.6, 每次的版本升级都会加⼊⼀些新的特性,PDF参考说明书也是从最初的100多页到现在的1000多页,但是PDF⽂件格式的主要特性还是没有改变,可以这么理解,PDF1.6是PDF1.0的扩展集,学习了PDF1.0以后也能基本上理解PDF1.6的内容, ⽽PDF1.0规范是相对简单的,因此说我选择⼀个符合PDF1.0规范的最简单的⼀个PDF⽂件来进⾏分析。
PDF规范的6次升级:
1.1 1995 加⼊了⽂档加密(40字节),线索树,名字树,链接,设备独⽴⾊彩资源。
1.2 1996 表单, 半⾊调屏幕,和其他的⼀些⾼级⾊彩特性, 对中⽂,⽇⽂和韩⽂的⽀持
1.3 2000 数字签名, 逻辑结构, JavaScript, 嵌⼊式⽂件,Masked Images, 平滑阴影, ⽀持 CID字体的附加⾊彩。
1.4 2001 ⽂件加密 (128 字节), 标签式 PDF, 访问控制,透明,元数据流
1.5 2003 ⽂档加密 (公钥), JPEG 2000 压缩, 可选的内容组,附加的注解类型
1.6 2005 ⽂档加密 (AES),增加最⼤⽂件⽀持,加⼊3D⽀持,额外的注解类型
3.PDF⽂件的基本组成:
⼀个PDF⽂件从⼤的⽅⾯来说可以分4个部分:
⽂件头,指明了该⽂件所遵从的PDF规范的版本号,它出现在PDF⽂件的第⼀⾏。
⽂件体,PDF⽂件的主要部分,由⼀系列对象组成。
交叉引⽤表,为了能对间接对象进⾏随机存取⽽设⽴的⼀个间接对象的地址索引表。
⽂件尾,声明了交叉引⽤表的地址,即指明了⽂件体的根对象(Catalog),从⽽能够到PDF⽂件中各个对象体的位置,达到随机访问。另外还保存了PDF⽂件的加密等安全信息(以后详细讨论)。
如下图:
图 1
4.PDF⽂档的逻辑结构
作为⼀种结构化的⽂件格式,⼀个PDF⽂档是由⼀些称为“对象”的模块组成的。并且每个对象都有数
字标号,这样的话可以这些对象就可以被其他的对象所引⽤。这些对象不需要按照顺序出现在PDF⽂档⾥⾯,出现的顺序可以是任意的,⽐如⼀个PDF⽂件有3页,第3页可以出现在第1页以前,对象按照顺序出现唯⼀的好处就是能够增加⽂件的可读性,如果你不会⽤⽂本编辑器来阅读PDF结构,那么⼤可不必关⼼该顺序。正是因为页与页之间的不相关性,就能够对PDF⽂件的页⾯进⾏随机的访问。
⽂件尾(Trail),说明根对象的对象号,并且说明交叉引⽤表的位置,通过对交叉引⽤表的查询可以到⽬录对象(Catalog)。这个⽬录对象是该PDF⽂档的根对象,包含PDF⽂档的⼤纲(outline)和页⾯组对象(pages)引⽤。⼤纲对象是指PDF⽂件的书签树;页⾯组对象(pages)包含该⽂件的页⾯数,各个页⾯对象(page)的对象号。
下图是PDF⽂档的层次关系:
图 2
页⾯(page)对象作为PDF中最重要的对象,包含如何显⽰该页⾯的信息,例如使⽤的字体,包含的内容(⽂字,图⽚等),页⾯的⼤⼩。⾥⾯的信息可以直接给出,当然⾥⾯的⼦项更多的是对其他对象的引⽤,真正的信息存放在其他对象⾥⾯。页⾯中包含的信息是包含在⼀个称为流(stream)的对象⾥,这个流的长度(字节数)必须直接给出或指向另外⼀个对象(包含⼀个整数值,表明这个流的长度)。如下图:
图 3
5. PDF的基本语法:
⽂件的第⼀⾏是⽂件头,指明了该⽂件所遵从的PDF规范的版本号,它出现在PDF⽂件的第⼀⾏。
⼀个对象的第⼀⾏⼀般有两个数字和关键字“obj”。例如:
1. 3 0 obj
2. <<
节约用水的作文3. /Type /Pages
4. /Count 1
汽车仪表盘
5. /Kids [4 0 R]
6. >>
7. endobj
第⼀个数字称为对象号,来唯⼀标识⼀个对象的,第⼆个是产⽣号,是⽤来表明它在被创建后的第⼏
艾美奖2016次修改,所有新创建的PDF⽂件的对象号应该都是0,即第⼀次被创建以后没有被修改过。上⾯的例⼦就说明该对象的对象号是3,⽽且创建后没有被修改过。
对象的内容应该是包含在<< 和>>之间的,最后以关键字endobj结束.
6.⽂件Hello World的⽂件分析:
6.1.⽂件的具体分析
%PDF-1.0
⽂件头,说明符合PDF1.0规范
1. 1 0 obj
2. <<
3. /Type /Catalog
4. /Pages 3 0 R
5. /Outlines 2 0 R
6. >>
7. endobj
Catalog对象(根对象)
/Type /Catalog说明该对象的类型为/Catalog,/Pages 3 0 R,这⾥/Pages指的是这个根对象包含的/Pages的⽬标是对象号为3的对象,3 0 R的意思是对对象3的引⽤。
1. 2 0 obj
2. <<
3. /Type /Outlines
4. /Count 0
5. >>
6. endobj
outline对象(此处它的计数为0,说明没有书签)
1. 3 0 obj
2. <<
3. /Type /Pages
4. /Count 1
5. /Kids [4 0 R]
6. >>
7. endobj
pages对象(页⾯组对象),/Type /Pages 说明⾃⾝的属性,对象的类型为页码,/Count 1说明页码数量为1,/Kids [4 0 R]说明它的孩⼦、页的对象号为4,如果有多个页⾯,就有多个页⾯对象的引⽤,例如/Kids [4 0 R 10 0 R], 就说明该PDF的第⼀页的对象号是4,第⼆页的对象号是10。
1. 4 0 obj
2. <<
3. /Type /Page
4. /Parent 3 0 R
5. /Resources << /Font << /F1 7 0 R >> /ProcSet 6 0 R >>
6. /MediaBox [0 0 612 792]
7. /Contents 5 0 R
8. >>
9. endobj
页对象,/Parent 3 0 R说明其⽗对象的对象号为3,及Pages对象,/Resources << /Font << /F1 7 0 R >> /ProcSet 6 0 R >>说明该页所要包含的资源,包括字体和内容的类型,/MediaBox [0 0 612 792]说明页⾯的显⽰⼤⼩(以象素为单位),/Contents 5 0 R说明页⾯内容对象的对象号为5。
1. 5 0 obj
2. << /Length 44 >>
3. stream
4. BT
5. /F1 24 Tf
6. 100 100 Td (Hello World) Tj
7. ET
8. endstream
陆毅老婆鲍蕾9. endobj
<< /Length 44 >>说明stream对象为字节数,从BT开始,ET结束,包括中间的⾏结束符。