现在的位置: 首页 > 综合 > 正文

给程序员写的PDF文件格式入门

2013年03月09日 ⁄ 综合 ⁄ 共 4299字 ⁄ 字号 评论关闭

文章翻译自此处的部分

http://www.mactech.com/articles/mactech/Vol.15/15.09/PDFIntro/index.html

翻译的第五天了,每天用一小时。

                                                      PDF文件结构

一个规范的PDF文件可以分为四个主要部分(见图2):一个占一行的PDF(Header)

一个PDF主体(Body)

一个交叉引用表((Xref Table/Cross-Reference Table))

一个PDF(Trailer)


图2:一个规范PDF文件的结构

PDF头部(Header)

PDF文件的第一行指定了该PDF文件所属的版本,用PostScript(一款脚本语言)可以这样写:

%PDF-1.3

这条语句表明该文件符合PDF1.3的指定标准。在PostScript中,%在所有的注释前面,注释可以出现在文件的任何地方,注释所在的整行都是没有任何作用的(在字符串或流里面出现的分号不算注释喔!)。一般情况下,PDF文件的第二行也是一个注释,通常会包含一些“高位”(0x80-0xFF)的ASCII字符。这标示着邮件客户端或者其他文件中包含有其二进制数据的程序,所以第二行注释不会被当做ASCII文本。

PDF主体(Body)

一个PDF文件的主体部分包含了组成该文档内容的对象。这些对象一般包含字符串流,图像,数据,字体,注释等等(详细请看后面关于对象的进一步讲解)

主体部分也会包含大量看不见的对象来帮助实现文档的互动,安全特性和逻辑结构。

交叉引用表(Xref Table/Cross-Reference Table)

交叉引用表包含了文件中所有对象的偏移地址,这样如果需要定位一个元素的时候就不用大规模的扫描一个文件了(或者遍历某个链表)。如果文件没有被更新的话,交叉引用表会是一个连续的,包含单节的表,但是如果文件被修改之后,新的节就会被添加进来。

对于交叉引用表的每个节,都会有一些子节,每个子节对应着数块标号连续的对象。每一项对象都占20个字节(包括行尾字符)。开头10个字节用一个10位的数字指定对象的偏移,一个空格分隔符紧跟在后,然后一个5位数的数字指定对象的产生号,再来一个空格,然后用字符fn来表明这个对象是否被用到,最后是一个行尾结束符(有三个符合要求的行尾结束符,分别为0x200A, 0x200D或者0x0D0A)。其实实例演示下比描述这个表更好,所以这里我提供一个例子,其中的交叉引用表包含7个对象,被安插在四个子节里。

xref

0 1

0000000023 65535 f

3 1

0000025324 00000 n

21 4

0000025518 00002 n

0000025632 00000 n

0000000024 00001 f

0000000000 00001 f

36 1

0000026900 00000 n

(行尾结束符省略)

第一个包含单个对象(对象0)的子节比较特殊,它的意义在后面一点再讨论。第二个子节列了一个对象3(对象3的偏移是25324字节)。第三个子节列了四个对象,第一个是对象21,其他对象的索引是连续的,所以它们分别是22,23,24。第四个子节只有一个对象,就是对象36

所有的对象都会以f或者n标记以表明这个对象是否被用到。更标准的术语应该是说这个对象有效还是无效。“未被用到”意味着这个对象是存在在这个文件里的,但是它是过时的,不应该被使用。“被用到”则相反,它意味着这个对象是有效的,可以使用的(它的意思不是“已经被用了,你不能再用了”)。标志着n的对象的产生号前是该对象的偏移,而标志着f的对象的产生号前则是下一个无效对象的产生号。当一个无效对象被“复活”(变为有效)时,就又会使用产生号而不是偏移量了。

交叉引用表中的第一个对象总是无效的,而且产生号总是65535,它是无效对象链表中的链头。最后一个无效对象(链尾)使用0作为下个无效对象的产生号。

看了这个例子之后现在你知道这些语句的作用了吧。注意:对象0指向表中的下一个无效对象,也就是对象23。因为对象23是无效的所以它在表里占的那一项不是以其偏移开头而是以下一个无效对象的指针开头,也就是24.但是对象24恰好是文件中的最后一个对象所以对象24在表中是以0000000000开头的

一般来说,一个对象被释放时,其产生号会被增加。这就是为什么对象23和对象24会有着值为1的产生号了。如果对象被复活了,其所对应的项的标志会从f变为n,然后也会使用字节偏移量来表明对象的位置,产生号仍然是1,当这对象又被释放的时候,标志又会变成f,产生号就会变成2,以此类推。

PDF尾部(Trailer)

PDF文件尾部使得一个程序能够快速找到交叉引用表和某些特殊对象(应用程序一般从后往前读PDF文件)。一个PDF文件的最后一行仅包含文件结束标志,也就是%%EOF。再前面两行包含关键字“startxref”以及在交叉引用表最后一个节中的关键字“xref”的字节偏移。再上面就是“尾部字典”。然后PDF尾部的最顶层就是关键词“trailer”了。就像这样:

trailer

<<

/Size 22

/Root 2 0 R

/Info 1 0 R

>>

startxref

24212

%%EOF

The byte offset from the start of the file to the start of the word xref at the top of the cross-reference table is, in this instance, 24,212. 

“xref”的字节偏移在此例中是24212

The trailer dictionary consists of everything between the double angle brackets, << and >>. 

尾部字典的所有内容包含在双角括号<<>>中。

The mandatory /Size key gives the total number of entries in all sections of the document's xref table. 

/Size这一项是必须有的,它指定了交叉索引表的所有对象的数目。

/Root这一项也是必须有的,它提供了对一个特殊类型的对象的指向,这个对象叫做目录对象,它包含了各种对象树(对象树包含了文档的内容)的根。

/Info这一项是可选的,它提供了对一个特殊的字典的指向,这个字典包含关于了一些会出现在Acrobat查看器的文档信息对话框里的信息。

增量更新机制(The Incremental Update Mechanism)

PDF尾部在PDF文件修改中起很大作用。在此有一个很关键的概念就是:PDF文件从来都不会被覆写,而只会被增加些什么。这一点对PDF文件任何位置的修改都是成立的,即使是PDF的尾部,甚至是文件结束符。换句话来说,一个被修改多次的PDF文档可能会包含几个尾部,甚至几个文件结束符呢!文件每次被编辑之后,都会有信息被添加到文件尾部,这些信息包含了内容变更了的对象,一个新的交叉引用表,以及一个包含了前PDF尾部所有信息的新PDF尾部,同时也新添了一个/Prey键来指定之前的交叉引用表的偏移地址。交叉引用表的信息可能会指向其他的交叉引用表,所以如果读者要访问所有交叉引用表的话就必须以逆序遍历所有的/Prev

由于篇幅关系,不能与您细谈文件更新的问题,但是你可以在PDF1.3手册的附录A里面找到几个相关的例子(http://partners.adobe.com/asn/developer)

PDF数据类型(Data Types

基本上PDF7种对象:布尔,数字,名字,字符串,数组,字典还有流(严格来说还有一个NULL对象)。任何对象都可以被赋予名字以方便其他对象的引用。当一个对象被赋予名字,这个对象叫做非直接对象。在这里主要需要掌握的概念就是“非直接”,这在很多情况下都非常有用(欲知详情,下回分解)

布尔型(Booleans)

在PDF里面,关键字“True”和“False”分别代表布尔对象的值“非0”和“0”。(注意,巧合的是,PDF是大小写敏感的,“True”和“TRUE”是不一样的喔!)

数字型(Numbers)

PDF支持两种类型的数字:整数型(32位有符号)和实数(±32767,最小值是65535的倒数)。有一些异常形式的数字如1.0E4是不支持的。

名字型(Names)

一个名字是一系列以“/”字符开始,范围从0x210x71的ASCII字符(除了这些字符“%, (, ), <, >, [, ], {, }, /, #”)。除了NULL之外的任何字符都可以被其对应的单字节的hex数字表示(字符是以“#”开头)。对一个名字来说最多容许127个字符。例子如下:

/Contents

/Chap6_Section1

/Chap6#5FSection1

/Name#20with#20spaces

/1.5

/.end

字符串型(Strings)

在PDF里面,也就是在PostScript里面,一个字符串包含一系列被括号括住的8位字符。字符串的最大长度可以是65535字节。当一行容纳不了一个太长的字符串时,你可以在行尾放一个符号“\”把这字符串分成N部分,“\”符号是不会被看做是字符串的。例:

( This is a valid string. )

( This is a somewhat longer \

string, split across \

three lines. )

任何的8位值都可以用8进制(\dddddd是那个八进制数)或者尖括号包住的单字节十六进制数表示,如下:

(Two + two = four.)

(Two \053 two \075 four.)

(Two <2B> two <3D> four.)

(<54776F202B2074776F203D20> four.)

在PostScript中,诸如\r, \t等格式控制字符都可以用在PDF字符串里。

数组(Arrays)

一个数组是被方括号包含的任意类型的PDF序列,而且不一定所有类型都必须一样。如下:

[ 1 2 3 6.25 ]  % an array of numbers

[ true /Chap9 3.14 (yes) ] % array of misc. objects

字典(Dictionaries)

未完待续



抱歉!评论已关闭.