本文是对PDF Explained(by John Whitington)第四章《Document Structure》的摘要式翻译。
本章我们来看PDF的逻辑结构,涉及trailer字典,文档目录(document catalog)和页面树以及PDF中两种常见结构:文本字符串和日期。
一个典型的PDF文档逻辑结构如下图所示:
这份字典位于文件尾部而不是文件的主体中,如果程序想要读取PDF文档,首先要做的就是处理trailer字典。 字典中的重要条目如下表所示,*表示必选条目。
键 | 值类型 | 值 |
---|---|---|
/Size* | 整数 | 交叉引用表中的条目总数(通常等于文件中的对象个数加1) |
/Root* | 间接引用字典 | 文档目录 |
/Info | 间接引用字典 | 文档信息字典 |
/ID | 两个字符串的数组 | 文件在工作流中唯一标识。第一个字串在文件首次创建时确定,第二个字串随工作流系统对文件的修改而修改。 |
下面是一个trailer字典的例子:
<<
/Size 421
/Root 377 0 R
/Info 375 0 R
/ID [<75ff22189ceac848dfa2afec93deee03> <057928614d9711db835e000d937095a2>]
>>
处理了trailer字典后,我们就可以继续读取文档信息字典和文档目录。
文档信息字典包含文件的创建日期和修改日期,以及一些简单的元数据。
文档信息中的条目如下表所示,表中提到的“文本字串”和日期字串将在后文中详述。
键 | 值类型 | 值 |
---|---|---|
/Title | 文本字串 | 文档标题。请注意,这与第一页上显示的任何标题无关。 |
/Subject | 文本字串 | 文档主题。同样,这只是元数据,没有关于内容的特定规则 |
/Keywords | 文本字串 | 文档关键字。 |
/Author | 文本字串 | 文档作者 |
/CreationDate | 日期字串 | 文档创建日期 |
/ModDate | 日期字串 | 文档最后修改日期 |
/Creator | 文本字串 | 最初创建此文档的程序的名称。文档起初可能是其它格式,比如Microsoft Word。 |
/Producer | 文本字串 | 将此文件转换为PDF的程序的名称。 |
一个典型的文档信息字典如下例所示:
<<
/ModDate (D:20060926213913+02'00')
/CreationDate (D:20060926213913+02'00')
/Title (catalogueproduit-UK.qxd)
/Creator (QuarkXPress: pictwpstops filter 1.0)
/Producer (Acrobat Distiller 6.0 for Macintosh)
/Author (James Smith)
>>
文档目录是对象图的根对象(节点),从它出发可以通过间接引用触达所有其他对象。下表列出了文档目录中的条目,*为必选条目。
键 | 值类型 | 值 |
---|---|---|
/Type* | 名称 | 必须是/Catalog |
/Pages* | 间接引用字典 | 页面树的父节点 |
/PageLabels | 编号树(number tree) | 一棵编号树,给出了该文档的页面标签。这种机制允许文档中的页面具有比1,2,3更复杂的编号方式…例如,书籍的前言可以编号为i,ii,iii …而主要内容 再次以1,2,3开始…这些页面标签仅用于在PDF查看器中显示,与打印输出无关。 |
/Names | 字典 | 名称字典,名称到条目的映射。 |
/Dests | 字典 | 该字典将名称映射至目的地。目的地是对超链接跳转位置的描述。 |
/ViewerPreferences | 字典 | 查看器首选项字典,用于指定文档在屏幕的显示方式,例如缩放比例等。 |
/PageLayout | 名称 | 指定PDF查看器使用的页面布局。值为/SinglePage,/OneColumn,/TwoColumnLeft,/TwoColumnRight,/TwoPageLeft,/TwoPageRight。(默认值:/SinglePage)。详情见ISO 32000-1:2008的表28 |
/PageMode | 名称 | 指定PDF查看器使用的页面模式。值为/UseNone,/UseOutlines,/UseThumbs,/FullScreen,/UseOC,/UseAttachments。 (默认值:/UseNone)。详情见ISO 32000-1:2008的表28 |
/Outlines | 间接引用字典 | 大纲字典是文档大纲的根,通常称为书签 |
/Metadata | 间接引用流 | 文档的XMP元数据 |
由页面字典构建的页面树汇集了用于绘制图形和文本内容的指令以及相关的资源(字体,图片,外部数据)。同时还包含页面大小,以及一些裁剪框。
下表列出了页面字典中的条目,*为必选条目。
键 | 值类型 | 值 |
---|---|---|
/Type* | 名称 | 必须为/Page |
/Parent* | 间接引用字典 | 当前节点的父节点 |
/Resources | 字典 | 页面资源(字体、图片等)。如果省略这项,所需资源将从页面树中的父节点继承。如果的确无需任何资源,请保留些项,使用空字典。 |
/Contents | 对数组,流等的间接引用 | 页面的图形内容。如果缺少此条目,则页面为空。 |
/Rotate | 整数 | 页面旋转角度,单位:度。值必须是90的倍数。默认值:0。这适用于查看和打印。如果缺少此条目,则其值将从父节点继承。 |
/MediaBox* | 长方形 | 页面的媒体框。大多数情况指页面大小。如果缺少此条目,将从父节点继承。 |
/CropBox | 长方形 | 页面的裁剪框。定义了在显示或打印页面时默认的可见区域。如果不存在,则取媒体框的值。 |
用于媒体框和其它框的矩形数据结构是包含四个数字的数组。它们定义了矩形的对角–数组的前两个元素是一个角的x和y坐标,后两个元素是另一个角的x和y坐标。 通常给出的是左下角和右上角。例如:
/MediaBox [0 0 500 800]
/CropBox [100 100 400 700]
定义一个500 x 800点的页面,裁剪框在页面的每一侧保留100个点。
页面通过页面树链接在一起。设计良好的PDF应用程序会构建一棵平衡树(具有最小高度的树)。这可确保任何页面均可被快速定位。没有子节点的节点(页节点)就是页面。 下图显示了由七个页构成的页面树。
该页面树对应的对象如下:
1 0 obj Root node
<< /Type /Pages /Kids [2 0 R 3 0 R 4 0 R] /Count 7 >>
endobj
2 0 obj Intermediate node
<< /Type /Pages /Kids [5 0 R 6 0 R 7 0 R] /Parent 1 0 R /Count 3 >>
endobj
3 0 obj Intermediate node
<< /Type /Pages /Kids [8 0 R 9 0 R 10 0 R] /Parent 1 0 R /Count 3 >>
endobj
4 0 obj Page 7
<< /Type /Page /Parent 1 0 R /MediaBox [0 0 500 500] /Resources << >> >>
endobj
5 0 obj Page 1
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 500 500] /Resources << >> >>
endobj
6 0 obj Page 2
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 500 500] /Resources << >> >>
endobj
7 0 obj Page 3
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 500 500] /Resources << >> >>
endobj
8 0 obj Page 4
<< /Type /Page /Parent 3 0 R /MediaBox [0 0 500 500] /Resources << >> >>
endobj
9 0 obj Page 5
<< /Type /Page /Parent 3 0 R /MediaBox [0 0 500 500] /Resources << >> >>
endobj
10 0 obj Page 6
<< /Type /Page /Parent 3 0 R /MediaBox [0 0 500 500] /Resources << >> >>
endobj
中间节点及根节点使用的条目如下(*为必选)
键 | 值类型 | 值 |
---|---|---|
/Type* | 名称 | 必须是/Pages |
/Kids* | 间接引用数组 | 该节点的直接子页面树节点。 |
/Count* | 整数 | 该节点的子节点数量 |
/Parent | 页面树节点的间接引用 | 指向该节点的父节点。除根节点外,所有节点必须有此条目。 |
页面实际文本内容之外的字符串(例如,书签名称,文档信息等)被称为文本字符串。 它们使用PDFDocEn编码或Unicode编码(使用更广)。
编码为Unicode的文本字符串通过查看前两个字节来区分:这些字符将是254后跟255.这是Unicode字节顺序标记U + FEFF,表示UTF16BE编码。 这意味着PDFDocEncoding字符串不能以þ(254)后跟ÿ(255)开头,但这在任何合理的情况下都不太可能发生。
日期字符串的格式为: (D:YYYYMMDDHHmmSSOHH’mm’)
其中括号表示字符串。其他部分的含义如下表所示。
串 | 含义 |
---|---|
YYYY | 四位年份,例如2008年 |
MM | 月份,从01到12的两位数 |
DD | 日期,从01到31的两位数 |
HH | 小时,从00到23的两位数 |
mm | 分钟,从00到59两位数 |
SS | 秒,从00到59两位数 |
O | 本地时间与世界时的关系,取值为:+,- 或Z。分别表示晚于, 早于,等于世界时间。 |
HH’ | 世界时间的小时偏差,从00到23的两位数 |
mm’ | 世界时间的侰偏差,从00到23的两位数 |
年份之后的部分都是可选的。例如,(D:1999)就是全法有效的。DD和MM的默认值为01,对于所有其他部分,默认值为零。例如:(D:20060926213913+02’00’) 代表2006年9月26日下午9:39:13,比世界时间早两个小时的时区。
下面这是一个手动创建的文本,它是一个三页的文档。
%PDF-1.1 //Header
1 0 obj //Top-level of page tree: has two children—page one and an intermediate page tree node
<< /Kids [2 0 R 3 0 R] /Type /Pages /Count 3 >>
endobj
4 0 obj //Contents stream for page one
<< >>
stream
1. 0.000000 0.000000 1. 50. 770. cm BT /F0 36. Tf (Page One) Tj ET
endstream
endobj
2 0 obj //Page one
<<
/Rotate 0
/Parent 1 0 R
/Resources
<< /Font << /F0 << /BaseFont /Times-Italic /Subtype /Type1 /Type /Font >> >> >>
/MediaBox [0.000000 0.000000 595.275590551 841.88976378]
/Type /Page
/Contents [4 0 R]
>>
endobj
5 0 obj //Document catalog
<< /PageLayout /TwoColumnLeft /Pages 1 0 R /Type /Catalog >>
endobj
6 0 obj //Page three
<<
/Rotate 0
/Parent 3 0 R
/Resources
<< /Font << /F0 << /BaseFont /Times-Italic /Subtype /Type1 /Type /Font >> >> >>
/MediaBox [0.000000 0.000000 595.275590551 841.88976378]
/Type /Page
/Contents [7 0 R]
>>
endobj
3 0 obj //Intermediate page tree node, linking to pages two and three
<< /Parent 1 0 R /Kids [8 0 R 6 0 R] /Count 2 /Type /Pages >>
endobj
8 0 obj //Page two
<<
/Rotate 270
/Parent 3 0 R
/Resources
<< /Font << /F0 << /BaseFont /Times-Italic /Subtype /Type1 /Type /Font >> >> >>
/MediaBox [0.000000 0.000000 595.275590551 841.88976378]
/Type /Page
/Contents [9 0 R]
>>
endobj
9 0 obj //Content stream for page two
<< >>
stream
q 1. 0.000000 0.000000 1. 50. 770. cm BT /F0 36. Tf (Page Two) Tj ET Q
1. 0.000000 0.000000 1. 50. 750 cm BT /F0 16 Tf ((Rotated by 270 degrees)) Tj ET
endstream
endobj
7 0 obj Content stream for page three
<< >>
stream
1. 0.000000 0.000000 1. 50. 770. cm BT /F0 36. Tf (Page Three) Tj ET
endstream
endobj
10 0 obj //Document information dictionary
<<
/Title (PDF Explained Example)
/Author (John Whitington)
/Producer (Manually Created)
/ModDate (D:20110313002346Z)
/CreationDate (D:2011)
>>
endobj xref
0 11
trailer //Trailer dictionary
<<
/Info 10 0 R
/Root 5 0 R
/Size 11
/ID [<75ff22189ceac848dfa2afec93deee03> <75ff22189ceac848dfa2afec93deee03>]
>>
startxref
0
%%EOF
上述代码通过pdftk处理后即可在Acrobat Reader中展现。
对象图如下: