pdf解析(转)

pdf解析

最近看了个开源项目代码xpdf,从pdf文档中提取文本,用于建全文索引,老外的代码什么都好,就是对中文支持不好,估计也是GNU标准惹的祸,但愿以后unicode横行的时候,我们这些chinese coder会过得更轻松一点。

没办法,只能自己看Adobe的官方资料http://www.adobe.com/,研究一下pdf的协议标准,下面是一片介绍pdf文档架构的文章。

Adobe的PDF参考告诉我们一个PDF文件可以通过下面4个方面来理解:

1.对象, 一个PDF文档是由一个由基本数据类型组成的数据结构。

2.文件(物理结构), 决定对象是如何存放在一个PDF文件中的, 它们是如何被访问的,如何被更新的。这个结构是独立于对象的语义的。

3.文档结构, 说明一些基本的对象类型是如何来表现PDF文档的成分的:页,字体,批注,和另外一些内容。

4.内容流.一个PDF文件内容流包含一系列的指令,描述页面的外观或其他图形实体的外观和文件内容。

但是当时对我来说要看懂这几行字是有很大的困难的,需要了解确切含义,必须看完后面的几十页上百页的内容并且要分析一下一个实际的PDF文件才能完全领会它的意思。

后来经过长时间的文档阅读,相关开发,并且具体地分析PDF文件后才把PDF文件的语法,文件的解析搞清楚。虽然说学习是痛并快乐着,但是对于当时我来说真的希望有一个人能够告诉我一个简单的例子,通过一个简单的例子来描述PDF的基本组成,它的解析原理和过程。因此下面我主要将以一个简单的例子来说明PDF的主要特性并给出一个简单的PDF文件的全景。

1.PDF格式和HTML,XML格式:

一个PDF文档从根本上来说是一个8字节序。其实PDF格式和我们已经熟知的HTML,XML等结构化的文件格式一样,包含有关键字,分隔符,数据等等。

不同的是PDF文件是按照二进制流的方式保存的,而html文件则是文本方式保存的。XML文件一般只包含数据本身,并没有把如何显示的信息放在其中,因此要显示一个XML文件还需要一个Schema文件才能显示,否则看到的将是所有的字节流;HTML包含了数据的同时也包含了一些关于如何显示的信息,但是HTML是基于文本存放的,是可读的,你打开一个HTML文件就能知道所有显示在浏览器里得文字。 另外就是HTML不能包含二进制流,它对图像文件的引用都是通过链接的,全部是外部文件的方式来实现的。

2.PDF规范的发展

PDF规范从1993年到现在,已经有过7个版本,六次版本升级,从最初的pdf1.0.6版本到现在的PDF1.6, 每次的版本升级都会加入一些新的特性,PDF参考说明书也是从最初的100多页到现在的1000多页,但是PDF文件格式的主要特性还是没有改变,可以这么理解,PDF1.6是PDF1.0的扩展集,学习了PDF1.0以后也能基本上理解PDF1.6的内容。 因此说我下面的例子是基于一个PDF1.0的最简单的一个PDF文件的分析。

PDF规范的发展升级:

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个部分:

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

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

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

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

如下图:


4.PDF文档的逻辑结构

作为一种结构化的文件格式,一个PDF文档是由一些称为“对象”的模块组成的。并且每个对象都有数字标号,这样的话可以这些对象就可以北其他的对象所引用。这些对象不需要按照顺序出现在PDF文档里面,出现的顺序可以是任意的,比如一个PDF文件有3页,第3页可以出现在第一页以前,对象按照顺序出现唯一的好处就是能够增加文件的可读性,如果你不会用文本编辑器来阅读PDF结构,那么大可不必关心。正是因为页与页之间的不相关性,就可以对PDF文件的页码进行随机的访问。

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

一个PDF文档有下图所示的层次关系:


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


5. PDF的基本语法:

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

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

3 0 obj

<<

/Type /Pages

/Count 1

/Kids [4 0 R]

>>

endobj

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

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

6. 文件Hello World的文件分析:

6.1.文件的具体分析

%PDF-1.0

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

1 0 obj

<<

/Type /Catalog

/Pages 3 0 R

/Outlines 2 0 R

>>

endobj

Catalog对象(根对象)

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 10 0 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 0 612 792]

/Contents 5 0 R

>>

endobj

页对象,/Parent 3 0 R说明其父对象的对象号为3,/Resources << /Font << /F1 7 0 R >> /ProcSet 6 0 R >>说明该页所要包含的资源,包括字体和内容的类型,/MediaBox [0 0 612 792]说明页面的显示大小(以象素为单位),/Contents 5 0 R说明页面内容对象的对象号为5。

5 0 obj

<< /Length 44 >>

stream

BT

/F1 24 Tf

100 100 Td (Hello World) Tj

ET

endstream

endobj

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

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

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

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

100 150 Td (Hello World) Tj,100 100 说明这一行文字放置的位置,对于Td, 我们可以这样理解,我们的当前X,Y坐标分别加上100和150就是文本的位置,因为在该例子中只有一个对象,那么它的位置就是(100,150), 如果下个对象位置信息为100, 50 Td, 那么它的位置应该就是(100+100, 150+50)也就是(200,200)。(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

Object six defines the

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

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

xref

0 8

0000000000 65535 f

0000000009 00000 n

0000000074 00000 n

0000000120 00000 n

0000000179 00000 n

0000000322 00000 n

0000000415 00000 n

0000000445 00000 n

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

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

0000000009 00000 n就是表示对象1,也就是catalog对象了,0000000009是其偏移地址,00000为5位产生号(最大为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为文件结束标志。

6.2.PDF解析过程


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,009评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,647评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,617评论 18 399
  • 西安市位于中国大陆腹地黄河流域中部的关中盆地,面积9983平方公里。人们常说:二十年中国看深圳,一百年中国...
    葬爱东少i阅读 336评论 0 2
  • 深入理解傅里叶变换Mar 12, 2017 这原本是我在知乎上对傅立叶变换、拉普拉斯变换、Z变换的联系?为什么要进...
    价值趋势技术派阅读 5,752评论 2 2