初步研究了下 PDF 的格式打算和大家分享一下如果.docx
- 文档编号:29565670
- 上传时间:2023-07-24
- 格式:DOCX
- 页数:19
- 大小:78.14KB
初步研究了下 PDF 的格式打算和大家分享一下如果.docx
《初步研究了下 PDF 的格式打算和大家分享一下如果.docx》由会员分享,可在线阅读,更多相关《初步研究了下 PDF 的格式打算和大家分享一下如果.docx(19页珍藏版)》请在冰豆网上搜索。
初步研究了下PDF的格式打算和大家分享一下如果
应该项目需要,初步研究了一下PDF的格式,打算和大家分享一下,如果有想做PDF或PDF阅读器开发的同学们,可以看看。
PDF格式规范,语法简洁。
但初次查看PDF却容易给人错觉——PDF的二进制流太多了,原本清晰的数据格式被杂乱无章的二进制流给淹没了。
例如:
Java代码
1.stream
2.5di?
倯?
貓?
匚{o绝幾Te:
馎HG
3.嵶?
W}?
妮雥?
?
隱q?
屸鷭鴊狳!
赭€?
鼜 ?
?
烖K柽z煜?
w?
?
?
鴚¬D¬h?
斜?
醱釓?
x?
i佲匃?
?
?
灗 Iu叁剪?
4.…………………………
stream
5di?
倯?
貓?
匚{o绝幾Te:
馎HG
嵶?
W}?
妮雥?
?
隱q?
屸鷭鴊狳!
赭€?
鼜?
?
烖K柽z煜?
w?
?
?
鴚¬D¬h?
斜?
醱釓?
x?
i佲匃?
?
?
灗Iu叁剪?
…………………………
像这样一大堆乱码的东西很多,所以,心理上无法耐心的继续看下去。
实际上PDF就是由四部分组成:
数据流的读写操作一般是从文件末尾开始的:
PDF所有的数据类型都是obj,强调的也是一切皆对象。
我简要的把PDF常见的几种数据类型给大家说说:
注意“%”表示注释
1. BooleanObjects:
只有true和false
2. NumericObjects:
● 整型:
123
● 浮点型-43.54,6.02E23
3. StringObjects:
● 文字型,用圆括号括起来,如:
(HelloWorld)
● 十六进制型,用尖括号括起来,如:
<901FA3>分别为90,1F,A3
4. NameObjects:
除null以外的任意8位字符组成的字符串,出现在PDF中,用“/”作前导符号,如:
/Name1。
其实这与编程中的常量很类似。
5. ArrayObjects:
PDF中的数组用方括号“[]”括起来,里面的数据可以完全不相同,如:
[5493.14false(Ralph)/SomeName]该数组里面分别装有5种不同的类型。
6. DictionaryObjects:
其实就类似于Java的Map对象——即以key,value的形式成对出现。
用的时候要用“<<…>>”把key,value括起来。
例如:
<>表示key为“name”的NameObjects,而value为“leo”字符串。
<<>>内部也可以嵌套使用,在PDF源文件中应用的非常广泛。
7. StreamObjects:
顾名思义,肯定有流有关。
这就是PDF中专门用于存放二进行流的对象。
PDF的实现者对StringObjects通常会做限制,但是StreamObjects却没有这样的限制。
因此streamobject用在图片,页面描述信息上是非常的适合的。
看看使用示例:
Java代码
1.7 0 obj %某一个Image类型的对象
2.<<
3./Type /XObject
4./Subtype /Image
5./Name /Im7
6./Width 189
7./Height 189
8./BitsPerComponent 8
9./ColorSpace [/Indexed /DeviceRGB 255 …>]
10./Mask [255 255]
11./Length 3832
12./Filter /FlateDecode
13.>> %紧接着这个对象定义后的Dictionary Objects对象后面
14.stream %定义它的Stream Objects
15.%这里放二进制流
16.endstream
70obj%某一个Image类型的对象
<<
/Type/XObject
/Subtype/Image
/Name/Im7
/Width189
/Height189
/BitsPerComponent8
/ColorSpace[/Indexed/DeviceRGB255…>]
/Mask[255255]
/Length3832
/Filter/FlateDecode
>>%紧接着这个对象定义后的DictionaryObjects对象后面
stream%定义它的StreamObjects
%这里放二进制流
endstream
8. NullObject:
区别与其它任何对象,用关键字null标注的对象就是nullobject。
9. IndirectObjects:
当然就是类似Java中的“引用”概念啦,举个例子就说明一切了。
Java代码
1.7 0 obj %有一个索引号为7 0的对象
2.<< /Length 8 0 R >> % 在它的Length属性引用了一个索引号为8 0的对象
3. %在这里“8 0 R”表示对8 0的对象引用(Reference)
4.stream
5.………….
6.endstream
7.endobj
8.
9.
10.8 0 obj %被上面7 0对象所引用的那个索引号为8 0的对象
11.77 %7 0对象的二进制流的长度
12.endobj
70obj%有一个索引号为70的对象
<>%在它的Length属性引用了一个索引号为80的对象
%在这里“80R”表示对80的对象引用(Reference)
stream
………….
endstream
endobj
80obj%被上面70对象所引用的那个索引号为80的对象
77%70对象的二进制流的长度
endobj
注意:
obj……endobjPDF文档组成的最小组成部分。
表示一个完整对象的定义
够了,说了这么多,让我们实战吧。
现在我们来看一个完整的示例,该示例可以在附件中下载。
看的时候,可以按照下面的步骤一步一步来分析PDF源文件:
Java代码
1.%PDF-1.3
2.%
3.2 0 obj %2 0 obj,里面是一些PDF的基本信息。
比如
4.<<
5./CreationDate (D:
20081029093606+08'00') %创建时间
6./ModDate (D:
20081029093606+08'00') %最后修改时间
7./Producer (leo 4.30 \(0615\)) %创建人
8./Creator (easyPDF SDK 4.3) %制作人
9.>> %你还可以自由的编写任何信息
10.endobj
11.
12.1 0 obj
13.<<
14./Count 0
15.>>
16.endobj
17.
18.3 0 obj %这是PDF的根结点(不是起始位置)
19.<<
20./Type /Catalog
21./Pages 4 0 R %这是所有页面的集合,我们主要关心这个
22./Outlines 1 0 R
23.>>
24.endobj
25.
26.7 0 obj
27.<<
28./Type /XObject
29./Subtype /Image
30./Name /Im7
31./Width 189
32./Height 189
33./BitsPerComponent 8
34./ColorSpace [/Indexed /DeviceRGB 255 <%这里放每个像素点的值>]
35./Mask [255 255]
36./Length 3832
37./Filter /FlateDecode
38.>>
39.stream
40.%这里放的全是图片的二进制流……..
41.endstream
42.endobj
43.
44.8 0 obj
45.<<
46./Length 51
47./Filter /FlateDecode
48.>>
49.stream
50.%这里放的全是图片的二进制流……..
51.endstream
52.endobj
53.
54.6 0 obj %重点分析一下这个
55.<<
56./Type /Page
57./Parent 4 0 R
58./MediaBox [ 0 0 595.276 841.89 ]
59./Resources <<
60./XObject <<
61./Im7 7 0 R
62.>>
63./ProcSet [/PDF /Text /ImageB /ImageC] >>
64./Contents 8 0 R
65.>>
66.endobj
67.
68.4 0 obj
69.<<
70./Type /Pages
71./Kids [
72.6 0 R %继续查找6 0 obj来看看具体的页面情况
73.]
74./Count 1
75.>>
76.endobj
77.
78.xref %索引,f表示该地址未被使用,n表示已经被占用。
79.0 9 %索引的顺序与对象在文中出现的序号是一致的,比如
80.0000000000 65535 f %默认占位符,不使用。
81.0000000177 00000 n %表示0 1 obj的偏移地址
82.0000000015 00000 n %表示0 2 obj的偏移地地 下面的以些类推
83.0000000208 00000 n
84.0000006159 00000 n
85.0000000000 00000 n %表示0 5 obj的偏移为0,可能被删除操作给干掉了。
86.0000005981 00000 n
87.0000000274 00000 n
88.0000005858 00000 n
89.trailer
90.<<
91./Size 9
92./Root 3 0 R %这个属性信息最重要,我们可以直接找到根结点
93./Info 2 0 R
94./ID[<112cbcc8320742d1cbe148d4ec0d7dba><112cbcc8320742d1cbe148d4ec0d7dba>]
95.>>
96.startxref %PDF文件解析的起点
97.6219
98.%%EOF
%PDF-1.3
%
20obj%20obj,里面是一些PDF的基本信息。
比如
<<
/CreationDate(D:
20081029093606+08'00') %创建时间
/ModDate(D:
20081029093606+08'00') %最后修改时间
/Producer(leo4.30\(0615\)) %创建人
/Creator(easyPDFSDK4.3) %制作人
>> %你还可以自由的编写任何信息
endobj
10obj
<<
/Count0
>>
endobj
30obj%这是PDF的根结点(不是起始位置)
<<
/Type/Catalog
/Pages40R%这是所有页面的集合,我们主要关心这个
/Outlines10R
>>
endobj
70obj
<<
/Type/XObject
/Subtype/Image
/Name/Im7
/Width189
/Height189
/BitsPerComponent8
/ColorSpace[/Indexed/DeviceRGB255<%这里放每个像素点的值>]
/Mask[255255]
/Length3832
/Filter/FlateDecode
>>
stream
%这里放的全是图片的二进制流……..
endstream
endobj
80obj
<<
/Length51
/Filter/FlateDecode
>>
stream
%这里放的全是图片的二进制流……..
endstream
endobj
60obj%重点分析一下这个
<<
/Type/Page
/Parent40R
/MediaBox[00595.276841.89]
/Resources<<
/XObject<<
/Im770R
>>
/ProcSet[/PDF/Text/ImageB/ImageC]>>
/Contents80R
>>
endobj
40obj
<<
/Type/Pages
/Kids[
60R%继续查找60obj来看看具体的页面情况
]
/Count1
>>
endobj
xref%索引,f表示该地址未被使用,n表示已经被占用。
09%索引的顺序与对象在文中出现的序号是一致的,比如
000000000065535f%默认占位符,不使用。
000000017700000n %表示01obj的偏移地址
000000001500000n %表示02obj的偏移地地下面的以些类推
000000020800000n
000000615900000n
000000000000000n %表示05obj的偏移为0,可能被删除操作给干掉了。
000000598100000n
000000027400000n
000000585800000n
trailer
<<
/Size9
/Root30R%这个属性信息最重要,我们可以直接找到根结点
/Info20R
/ID[<112cbcc8320742d1cbe148d4ec0d7dba><112cbcc8320742d1cbe148d4ec0d7dba>]
>>
startxref%PDF文件解析的起点
6219
%%EOF
第一步:
首先是先看文件末尾,找到它的“xref”和“trailer”部分。
Xref表示对象索引,其实就是对象在文件中的偏移地址(PDF源文件中是以10进制表示的,你转换成16进制后,用UE或者其它工具查看即可)。
Trailer虽然从字面上看是“尾部”的意思,但是解析却从它开始。
“startxref”表示文件的入口地址,像java的main()方法。
后面紧跟着一个10进制的数字,指向的是索引“xref”的位置。
Trailer里面的值分别表示:
1. Size9:
表示9个索引值
2. Root30R:
根结点是30obj的引用
3. Info20R:
相关信息是20obj的引用
4. ID:
类似于Java的Serializable机制,给本PDF文件生成一个独一无二的标识
第二步:
按照Root30R,我们向上查找,找到了我们要找的Root对象,里面的信息从字面上很容易理解:
1. /Type/Catalog:
表示该对象的类型是目录
2. /Pages40R:
表示所有的PDF页面在一个叫40R的对象上
3. /Outlines10R:
PDF文件的大纲,也就是左侧展示的东西。
继续查找40obj,果然与预期所想的一样,的确是所有页面的集合,并且还有一个附加属性Count统计页面对象的个数:
/Type/Pages:
表示该对象的类型是所有页面的集合
/Kids[…]:
这是一个数组,里面装的是每个页面的具体引用。
因为这个PDF就一页,所有只有一个“60R”。
下一步,就从这里入手。
/Count1:
页的总数大小,因为这个PDF就一页,所以值为1。
编程时可能会用到。
第三步:
来重点分析一下页对象
Java代码
1.6 0 obj %索引编号为6的对象,0表示该对象的修改次数
2.<< % << 表示是这一个map,里面的所有数据都以key,value形式出现
3./Type /Page %其类型为Page,表示PDF的每一页
4./Parent 4 0 R %其父结点为4 0对象(R表示引用,对象之间是可以双向引用的)
5./MediaBox [ 0 0 595.276 841.89 ] %当前页画布为MediaBox样式,后面的表示左上角与右下角坐标,这样就形成了一个矩形。
6./Resources << % Resources 又为一个map的嵌套
7./XObject << % XObject 也是一个map的嵌套
8./Im7 7 0 R % 在Xobject中定义了一个叫Im7的名称,引用了叫Im7的7 0对象(在我的PDF中,这是一个图片对象)
9.>>
10./ProcSet [/PDF /Text /ImageB /ImageC] >> % 打印时的参数设置
11./Contents 8 0 R % 这里是实际页面上的内容信息,引用的是8 0对象
12.>>
13.endobj % 对象定义结束
60obj%索引编号为6的对象,0表示该对象的修改次数
<<%<<表示是这一个map,里面的所有数据都以key,value形式出现
/Type/Page%其类型为Page,表示PDF的每一页
/Parent40R%其父结点为40对象(R表示引用,对象之间是可以双向引用的)
/MediaBox[00595.276841.89]%当前页画布为MediaBox样式,后面的表示左上角与右下角坐标,这样就形成了一个矩形。
/Resources<<%Resources又为一个map的嵌套
/XObject<<%XObject也是一个map的嵌套
/Im770R%在Xobject中定义了一个叫Im7的名称,引用了叫Im7的70对象(在我的PDF中,这是一个图片对象)
>>
/ProcSet[/PDF/Text/ImageB/ImageC]>>%打印时的参数设置
/Contents80R%这里是实际页面上的内容信息,引用的是80对象
>>
endobj%对象定义结束
对于我们来说,以下是项目开发的重点。
因为要实现PDF文件盖章的添加或删除功能,必须进行流操作,并且图片在PDF文件的位置也要写入。
● /XObject<<>>:
里面持有图片等二进制的引用。
通过上述的方法,当你再查看70obj时,就会看到大量的二进制文件了。
● /Contents:
是文件的内容信息。
比如说,页面上的文本,图片的坐标位置等。
通过这个完整的流程,你应该明白PDF的格式其实就是一个层次分明的树形结构。
不过,想完全了解PDF的格式,进行相关的操作。
你还得参看PDF规范文档。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 初步研究了下 PDF 的格式打算和大家分享一下如果 初步 研究 格式 打算 大家 分享 一下 如果