PDF结构分析

一、   简单了解PDF

1   PDF格式

一个PDF文档从根本上来说是一个8字节序列。 其实PDF格式和我们已经熟知的HTML,XML等结构化的文件格式一样,包含有关键字,分隔符,数据等等。不同的是PDF文件是按照二进制流的方式保存的,而html文件则是可读的文本方式保存的。

2   PDF规范的发展

PDF规范的6次升级:

1.11995 加入了文档加密(40字节),线索树,名字树,链接,设备独立色彩资源。

1.21996 表单, 半色调屏幕,和其他的一些高级色彩特性, 对中文,日文和韩文的支持

1.32000 数字签名, 逻辑结构, JavaScript, 嵌入式文件,Masked Images, 平滑阴影, 支持 CID字体的附加色彩。

1.42001 文件加密 (128 字节), 标签式 PDF, 访问控制,透明,元数据流

1.52003 文档加密 (公钥), JPEG 2000 压缩,可选的内容组,附加的注解类型

1.62005 文档加密 (AES),增加最大文件支持,加入3D支持,额外的注解类型

3   PDF文件的基本组成

这四部分分别为:

文件头,指明了该文件所遵从的PDF规范的版本号,它出现在PDF文件的第一行。

l         文件体,PDF文件的主要部分,由一系列对象组成。

l         交叉引用表,为了能对间接对象进行随机存取而设立的一个间接对象的地址索引表。

l         文件尾,声明了交叉引用表的地址,即指明了文件体的根对象(Catalog),从而能够找到PDF文件中各个对象体的位置,达到随机访问。另外还保存了PDF文件的加密等安全信息

4   PDF文档的逻辑结构PDF

文件尾(Trailer),说明根对象的对象号,并且说明交叉引用表的位置,通过对交叉引用表的查询可以找到目录对象(Catalog)。这个目录对象是该PDF文档的根对象,包含PDF文档的大纲(outline)和页面组对象(pages)引用。大纲对象是指PDF文件的书签树;页面组对象(pages)包含该文件的页面数,各个页面对象(page)的对象号。

页面(page)对象作为PDF中最重要的对象,包含如何显示该页面的信息,例如使用的字体,包含的内容(文字,图片等),页面的大小。里面的信息可以直接给出,当然里面的子项更多的是对其他对象的引用,真正的信息存放在其他对象里面。页面中包含的信息是包含在一个称为流(stream)的对象里,这个流的长度(字节数)必须直接给出或指向另外一个对象(包含一个整数值,表明这个流的长度)

二、   文件结构

1. PDF的基础语法

文件的第一行是文件头,指明了该文件所遵从的PDF规范的版本号,它出现在PDF文件的第一行。

一个对象的第一行一般有两个数字和关键字“obj”。例如:

3 0 obj

<< 

/Type /Pages

/Count 1

/Kids [4 0 R]

>> 

endobj

第一个数字称为对象号,来唯一标识一个对象的,第二个是产生号,是用来表明它在被创建后的第几次修改,所有新创建的PDF文件的对象号应该都是0,即第一次被创建以后没有被修改过。上面的例子就说明该对象的对象号是3,而且创建后没有被修改过。

对象的内容应该是包含在<<和>>之间的,最后以关键字endobj结束.

2. PDF的解析过程

3. PDF的简单案例

%PDF-1.0        

文件头,说明符合PDF1.0规范

  

1 0 obj

<< 

/Type /Catalog

/Pages 3 0 R

/Outlines 2 0 R

>> 

endobj

Catalog对象(根对象)

/Type /Catalog说明该对象的类型为/Catalog/Pages 3 0 R,这里/Pages指的是这个根对象包含的/Pages的目标是对象号为3的对象,3 0 R的意思是对对象3的引用。

 

2 0 obj

<< 

/Type /Outlines

/Count 0

>> 

endobj

outline对象(此处它的计数为0,说明没有书签)

  

3 0 obj

<< 

/Type /Pages

/Count 1

/Kids [4 0 R]

>> 

endobj

pages对象(页面组对象),/Type /Pages 说明自身的属性,对象的类型为页码,/Count 1说明页码数量为1/Kids [4 0 R]说明它的孩子、页的对象号为4,如果有多个页面,就有多个页面对象的引用,例如/Kids [4 0 R 100 R], 就说明该PDF的第一页的对象号是4,第二页的对象号是10

 4 0 obj

<< 

/Type /Page

/Parent 3 0 R

/Resources<< /Font << /F1 7 0 R >> /ProcSet 6 0 R >>

/MediaBox [0 0612 792]

/Contents 5 0 R

>> 

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

 

5 0 obj

<< /Length44 >>

stream

BT

/F1 24 Tf

100 100 Td(Hello World) Tj

ET

endstream

endobj

 

<< /Length44 >>说明stream对象为字节数,从BT开始,ET结束,包括中间的行结束符。

Stream说明一个流对象的开始。

BT说明一个文字对象的开始。

/F1 24 TfTf说明True font对象,字体明为F1, 大小为24个象素。

100 150 Td(Hello World) Tj100 100 说明这一行文字放置的位置,对于Td, 我们可以这样理解,我们的当前X,Y坐标分别加上100150就是文本的位置,因为在该例子中只有一个对象,那么它的位置就是(100,150), 如果下个对象位置信息为100, 50 Td, 那么它的位置应该就是(100+100, 150+50)也就是(200200)。(Hello World Tj说明文本的内容,当然,如果这里是文本的内容写成16进制,则用<>包含。

ET说明文字对象的结束标志。

Endstream为流对象的结束标志

 

6 0 obj

[/PDF /Text]

Endobj

[/PDF /Text]说明PDF的内容类型仅仅为文本,如果有图片则为[/PDF /Image]

 

7 0 obj

<< 

/Type /Font

/Subtype /Type1

/Name /F1

/BaseFont/Helvetica

>> 

endobj

字体对象,不再多作解释。

所有的对象之后是下面的交叉引用表:

xref

0 8

0000000000 65535f

0000000009 00000n

0000000074 00000n

0000000120 00000n

0000000179 00000n

0000000322 00000n

0000000415 00000n

0000000445 00000n

xref说明一个交叉引用表的开始,交叉引用表的第一行0 8 说明下面各行所描述的对象号是从0开始,并且有8个对象。

0000000000 65535f,一般每个PDF文件都是以这一行开始交叉应用表的,说明对象0的起始地址为0000000000,产生号(generationnumber)为65535,也是最大产生号,不可以再进行更改,而且最后对象的表示是f, 表明该对象为free, 这里,大家可以看到,其实这个对象可以看作是文件头。

0000000009 00000n就是表示对象1,也就是catalog对象了,0000000009是其偏移地址,000005位产生号(最大为65535),0表明该对象未被修改过,  n表示该对象在使用,区别与自由对象,可以更改。

下面的几行相信大家就可以告诉我含义了。

Trailer

<< 

/Size 8

/Root 1 0 R

>> 

startxref

553

%%EOF

trailer

说明文件尾trailer对象的开始。

/Size 8说明该PDF文件的对象数目。

/Root 1 0 R说明根对象的对象号为1

Startxref

553说明交叉引用表的偏移地址,从而可以找到PDF文档中所有的对象的相对地址,进而访问对象。

%%EOF为文件结束标志。

4. 文件头

文件头是PDF文件的第一行,格式:  %PDF-1.4  

这是个固定格式,表示这个PDF文件遵循的PDF规范版本

5. 对象集合

这是一个PDF文件最重要的部分,文件中用到的所有对象,包括文本/图象/视频/字体/超连接/加密信息/文档结构信息等等,都在这里定义。格式如下:         

2 0 obj  

        ...  

end obj

一个对象的定义包含4个部分:

1):前面的2是对象序号,其用来唯一标记一个对象;

2): 0是生成号,按照PDF规范,如果一个PDF文件被修改,那这个数字是累加的,它和对象序号一起标记是原始对象还是修改后的对象,但是实际开发中,很少有用这种方式修改PDF的,都是重新编排对象号;

3):obj和endobj是对象的定义范围,可以抽象的理解为这就是一个左括号和右括号;

4):省略号部分是PDF规定的任意合法对象(一共8种)。

可以通过R关键字来引用任何一个对象,比如要引用上面的对象,可以使用2 0 R,需要主意的是,R关键字不仅可以引用一个已经定义的对象,还可以引用一个并不存在的对象,而且效果就和引用了一个空对象一样。

6. 交叉引用表

交叉引用表是PDf文件内部一种特殊的文件组织方式,可以很方便的根据对象号随机访问一个对象。其格式如下:      

  xref  

  0 1  

  0000000000  65535   f  

  4 1

0000000009   00000  n  

  8 3

0000000074   00000  n  

  0000000120  00000   n  

  0000000179  00000   n  

   

  其中,xref是开始标志,表示以下为一个交叉引用表的内容;每个交叉引用表又可以分为若干个子段,每个子段的第一行是两个数字,第一个是对象起始号,后面是连续的对象个数,接着每行是这个子段的每个对象的具体信息——每行的前10个数字代表这个这个对象相对文件头的偏移地址,后面的5位数字是生成号(用于标记PDF的更新信息,和对象的生成号作用类似),最后一位f或n表示对象是否被使用(n表示使用,f表示被删除或没有用)。上面这个交叉引用表一共有3个子段,分别有1个,1个,3个对象,第一个子段的对象不可用,其余子段对象可用。

7. Trailer

通过trailer可以快速的找到交叉引用表的位置,进而可以精确定位每一个对象;还可以通过它本身的字典还可以获取文件的一些全局信息(作者,关键字,标题等),加密信息,等等。具体形式如下:  

  trailer  

  <<  

    key1  value1

    key2  value2

    key3  value3

  >>  

  startxref  

  553  

  %%EOF      

 trailer后面紧跟一个字典,包含若干键-值对。具体含义如下:

startxref:   后面的数字表示最后一个交叉引用表相对于文件起始位置的偏移量。

%%EOF   :文件结束符.   

了解了PDF文件的物理结构,就可以提取出一个一个的对象了.PDF中的对象有8种:

1.booleam 

    用关键字true或false表示,可以是array对象的一个元素,或dictionary对象的一个条目.也可以用在PostScript计算函数里面,做为if或ifesle的一个条件。

2.numeric 

包括整形和实型,不支持非十进制数字,不支持指数形式的数字.      

    例: 

    1)整数 123   4567   +111  -2       

    范围:正2的31次方-1到负的2的31次方 

    2)实数 12.3   0.8   +6.3  -4.01   -3.   +.03 

    范围:±3.403   ×   10的38次方           ±1.175   ×   10的-38次方 

    注意:如果整数超过表示范围将转化成实数,如果实数超过范围就出错了 

3.string 

    由一系列0-255之间的字节组成,一个string总长度不能超过65535.string有以下两种方式: 

1)     直接字串

由()包含起来的一个字串,中间可以使用转义符"/". 

    例: 

    (abc) 表示abc 

    (a//) 表示a/ 

转义符的定义如下:

2)     十六进制字串

由<>包含起来的一个16进制串,两位表示一个字符,不足两位用0补齐

    例: 

    <Aabb> 表示AA和BB两个字符 

    <AAB> 表示AA和B0两个字符 

4.name 

    由一个前导/和后面一系列字符组成,最大长度为127.和string不同的是,name是不可分割的和唯一的,不可分割就是说一个name对象就是一个原子,比如/name,不能说n就是这个name的一个元素;唯一就是指两个相同的name一定代表同一个对象.从pdf1.2开始,除了ascii的0,别的都可以用一个#加两个十六进制的数字表示. 

    例: 

    /name 表示name 

    /name#20is 表示name is 

    /name#200 表示name 0  

5.array 

    用[]包含的一组对象,可以是任何pdf对象(包括array).虽然pdf只支持一维array,但可以通过array的嵌套实现任意维数的array(但是一个array的元素不能超过8191) 

    例: 

    [549  3.14   false   (Ralph)  /SomeName] 

6.Dictionary 

    用"<<"和">>"包含的若干组条目,每组条目都由key和value组成,其中key必须是name对象,并且一个dictionary内的key是唯一的;value可以是任何pdf的合法对象(包括dictionary对象). 

    例: 

    << /IntegerItem   12  

        /StringItem   (a  string) 

        /Subdictionary 

<<  /Item1  0.4 

            /Item2   true 

            /LastItem   (not!) 

            /VeryLastItem   (OK) 

        >> 

    >> 

7.stream 

    由一个字典,和紧跟其后面的一组关键字stream和endstream以及这组关键字中间包含一系列字节组成.内容和string很相似,但有区别:stream可以分几次读取,分开使用不同的部分,string必须作为一个整体一次全部读取使用;string有长度限制,但stream却没有这个限制.一般较大的数据都用stream表示. 需要注意的是,Stream必须是间接对象,并且stream的字典必须是直接对象。从1.2规范以后,stream可以以外部文件形式存在,这种情况下,解析PDF的时候stream和endstream之间的内容就被忽略掉。

    例:

dictionary

stream

… data …

endstream 

stream字典中常用的字段如下:

8.NULL 

    用null表示,代表空.如果一个key的值为null,则这个key可以被忽略;如果引用一个不存在的object则等价于引用一个空对象.

三、   逻辑结构

DF的逻辑大体上是一个树状结构,根节点是catalog字典,通过这里去解析页、目录、链接信息等等

catalog根节点

catalog是整个PDF逻辑结构的根节点,这个可以通过trailer的Root字段定位,虽然简单,但是相当重要,因为这里是PDF文件物理结构和逻辑结构的连接点。Catalog字典包含的信息非常多,这里仅就最主要的几个字段做个说明。

1)  Pages字段

这是个必须字段,是PDF里面所有页面的描述集合。Pages字段本身是个字典,它里面又包含了一下几个主要字段:

从以上字段可以看出,Pages最主要的功能就是组织所有的page对象。Page对象描述了一个PDF页面的属性、资源等信息。Page对象是一个字典,它主要包含一下几个重要的属性:

 

 

 

 

一个简单例子:

       30 obj

<< /Type/Page

/Parent 4 0 R

/MediaBox [ 0 0612 792 ]

/Resources<</Font<<

/F3 7 0 R /F5 90 R /F7 11 0 R

>> 

/ProcSet [ /PDF]

>> 

/Contents 12 0 R

/Thumb 14 0 R

/Annots [ 23 0 R24 0 R]

>> 

endobj

2)  Outlines字段

Outline是PDF里面为了方便用户从PDF的一部分跳转到另外一部分而设计的,有时候也叫书签(Bookmark),它是一个树状结构,可以直观的把PDF文件结构展现给用户。用户可以通过鼠标点击来打开或者关闭某个outline项来实现交互,当打开一个outline时,用户可以看到它的所有子节点,关闭一个outline的时候,这个outline的所有子节点会自动隐藏。并且,在点击的时候,阅读器会自动跳转到outline对应的页面位置。Outlines包含一下几个字段:

Outline是一个管理outline item的顶层对象,我们看到的,其实是outline item,这个里面才包含了文字、行为、目标区域等等。一个outlineitem主要有一下几个字段:

3)  URI字段

URI(uniform resource identifier),定义了文档级别的统一资源标识符和相关链接信息。目录和文档中的链接就是通过这个字段来处理的。

4)  Metadata字段

文档的一些附带信息,用xml表示,符合adobe的xmp规范。这个可以方便程序不用解析整个文件就能获得文件的大致信息。

5)  其他

Catalog字典中,常用的字段一般有以下一些:

四、   PDF的试验研究

1. PDF可添加外部信息的域

       如图,文中标识的部分,为可插入内容区域(有上限),不影响PDF的正常阅读使用。文件打开工具winhex,见邮件附件,显示格式为16进制。

      

2. PDF在合成PNG图片后的结构变化

上图为文件结构头部变化对比,下图为尾部文件对比,整体全部发生变化,整个内容结构全部重构了。

3. PDF结构在RSA国际算法签名后的变化

与合成PNG图片时候一致,从头到尾全部发生变化


猜你喜欢

转载自blog.csdn.net/P876643136/article/details/79449060
今日推荐