PDF(Portable Document Format)文件格式是Adobe公司开发的电子文件格式。这种文件格式与操作系统平台无关,也就是说,PDF文件不管是在Windows,Unix还是在苹果公司的Mac OS操作系统中都是通用的。这一特点使它成为在Internet上进行电子文档发行和数字化信息传播的理想文档格式。越来越多的电子图书、产品说明、公司文告、网络资料、电子邮件开始使用PDF格式文件。PDF格式文件目前已成为数字化信息事实上的一个工业标准。
PDF文件使用了工业标准的压缩算法,通常比PostScript文件小,易于传输与储存。它还是页独立的,一个PDF文件包含一个或多个“页”,可以单独处理各页,特别适合多处理器系统的工作。此外,一个PDF文件还包含文件中所使用的PDF格式版本,以及文件中一些重要结构的定位信息。正是由于 PDF文件的种种优点,它逐渐成为出版业中的新宠。
对普通读者而言,用PDF制作的电子书具有纸版书的质感和阅读效果,可以“逼真地”展现原书的原貌,而显示大小可任意调节,给读者提供了个性化的阅读方式。由于PDF文件可以不依赖操作系统的语言和字体及显示设备,阅读起来很方便。这些优点使读者能很快适应电子阅读与网上阅读,无疑有利于计算机与网络在日常生活中的普及。Adobe公司以PDF文件技术为核心,提供了一整套电子和网络出版解决方案,其中包括用于生成和阅读PDF文件的商业软件Acrobat和用于编辑制作PDF文件的Illustrator等。 Adobe还提供了用于阅读和打印亚洲文字,即中日韩文字所需的字型包。
一个最简单的PDF文件结构如下:
%PDF-1.4忏嫌
1 0 obj < /Pages 2 0 R
>>endobj
2 0 obj < /Kids [3 0 R]
/Count 1
>>endobj
3 0 obj < /Parent 2 0 R
/MediaBox [0 0 300 200]
/Contents 4 0 R
/Resources << /ProcSet [/PDF] >>
>>endobj
4 0 obj << /Length 00 >>
stream
endstream
endobj
xref
0 5
0000000000 65535 f
0000000014 00000 n
0000000071 00000 n
0000000146 00000 n
0000000297 00000 n
trailer << /Size 5
/Root 1 0 R
>>
startxref
350
%%EOF
第一行是PDF文件头,不同的PDF可能就是那个1.4会不同,因为那表示PDF文件的版本信息,最新的PDF版本已经到了1.7,后面的忏嫌可能也会有某些PDF不同,这两个其实是编码大于等于128的两个字符,是告诉其它应用程序该PDF中含有二进制信息。
然后可以看出编号为1、2、3、4的obj也就是对象,PDF是以对象为基本单位进行结构组织的,其中的1、2、3、4是对象号,其后紧跟的0是生成号,一般PDF中的这个号都是0,只有在别人修改了PDF中的某些内容的时候才会变成非0,后面的成对的<< >>是一个字典,上述的对象都是一个字典,字典里面有着成对的Key-Value,比如/Type就是Key表示该对象的类型,后面的/Pages或者/Page分别表示页面树和页面,在PDF里面页面是按照树形结构来组织的,但是这个树形结构与实际PDF内容的结构是没有关系的,它不影响PDF实际内容页面的顺序,每棵页面树都可能有它的子页面树,但最终的有内容的页面都只能是叶子结点。
注意,刚才所说的几个对象都是指间接对象,它们都有它们的编号,要引用这些对象的时候只需要写出它们的对象号、生成号,再在后面加一个R即可。
下面依次解释该PDF中的几个对象,对象1是整个PDF文件的目录对象,其/Type的值用/Catalog标示,/Pages的值则指明了页面树对象;对象2即是页面树对象,其/Kids的值是一个数组,用[]括起来,依顺序标识了该树的子树或者叶子对象,该文件只有一个叶子对象,/Count的值表示该页面树的所有叶子对象的数目,也就是说该PDF只有一页;对象3是一个叶子对象(页面对象),/Type的值为/Page,一个此对象就代表PDF中的一页,/Parent表示含有这个页对象的父页面树对象,/MediaBox的标识了该页面的大小,以磅为单位(72磅=1英寸=2.54厘米),/Contents表示该页面的内容对象,/Resource的值是一个字典,里面标识了该页面所用到的一些资源,对象4是页面的内容对象,该对象为一个流字典,因为其对象字典后面跟了用stream和endstream包含起来的一段二进制流,也称为内容流(在这个例子里面为空,表示该页没有内容),想在页面显示什么内容,只需要在这里面加相应的命令即可(具体命令见PDF Reference),前面字典里面的/Length的值表示其后的二进制流的长度(以字节为单位,不包stream、endstream以及endstream前面的换行符)。
对象4的结束标志endobj后面的xref一直到文件最后是PDF文件的交叉引用表和文件尾部分,PDF文件对象的查找都要用到交叉引用表和文件尾,其中文件尾包括从trailer开始一直到最后,可以看出trailer是一个字典,里面的/Size标志PDF的对象的个数(包括PDF默认的0号对象),/Root的值为整个文件的目录对象(即含有/Type /Catalog的对象)的间接引用,接下来的startxref也能从字面上猜出来,它标志着最后一个交叉引用表的起始位置(以字节为单位,交叉引用表的字符x(xref中的x)所在的位置减1,因为起始位置是从0开始的),一般应用程序读PDF都从文件末尾找startxref开始,最后的%%EOF是文件结束标志。
最后最重要的就是交叉引用表了,一般情况下,交叉引用表有trailer的/Size的值加上1行(不含xref那行),第一行有两个数,第一个表示该交叉引用表的起始对象号(此文件为0,是PDF自定义的对象0,无特殊作用),第二个表示该交叉引用表中的对象数,这里是5(也包括PDF自定义的0号对象),接下来的5行依次每行表示一个对象,每行的第一个是一个十位的非负整数,表示该对象的起始位置,第二个是一个5位的非负整数,表示该对象的生成数(最大为65535),最后一个是一个或者是f或者是n的字符,f表示该对象未被引用,n表示该对象已被引用,对象号为0的第一行较特殊,其起始位置为0,生成数为65535,最后一位是f,这是PDF的规定,不能改变。在读取对象信息的时候,就是靠着这个交叉引用表找到各对象位置进行解析的。依次交叉引用表一旦被破坏,你的PDF就不能被应用程序(如Adobe Acrobat Reader)打开了。
最后一点,如果你想要将文中的代码令存为一个PDF,然后用Acrobat打开它的话,你很可能会失望了,因为我从UltraEdit里面拷贝过来的时候里面的一些涉及到换行的一些字符很可能会被改变,所以对象的位置也会相应的改变,交叉引用表中的数值又没有变,当然打不开了,要想打开,你可以把存的PDF用UltraEdit重新打开,切换到二进制视图(一定不能在文本视图下保存),查每个对象的位置(将光标移到对象号的字符前面,UltraEdit状态栏会显示十六进制的光标位置和十进制的光标位置),将十进制的正确的光标位置填到相应的交叉引用表中的字段即可(填的时候最好是用替换模式而不是删除模式,按退格键右边的Insert键可以切换这两种模式),4个对象的位置都填好后在二进制模式下保存,然后再用Acrobat Reader打开来看看,如果能够打开不报错,就证明你大功告成了!虽然我们只能看到一个什么都没有的空白页面,但好歹这也是我们自己手工制作的第一个PDF文件。然后你可以试着改/MediaBox的值的大小,看看有什么效果?