diff --git a/chapter2.md b/chapter2.md index 9a38bcd..fd4401d 100644 --- a/chapter2.md +++ b/chapter2.md @@ -1,12 +1,11 @@ # 第2章 - 构建一个简单的PDF -在本章中,我们将在文本编辑器中手动构建PDF内容。然后我们将使用 -免费的*pdftk*程序将其转换为有效的PDF文件,并在PDF查看器中查看输出。 +在本章中,我们将在文本编辑器中手动构建PDF。然后我们将使用 +免费的*pdftk*工具将其转换为有效的PDF文件,并在PDF查看器中查看。 此示例以及本书中的所有PDF文件都可以从中这本书的[网页](https://resources.oreilly.com/examples/0636920021483/)下载。 -我们将同时考虑很多新概念,所以不要担心, -如果看起来压倒一切 - 我们将在以后的章节中回到这一切。 +我们会遇到很多新概念,但不要担心,我们将在后面的章节中详细讨论它们。 补充pdftk介绍信息 @@ -15,7 +14,7 @@ PDF文件至少包含三种不同的语言: * *document content*文档内容,是在它们之间具有链接的多个对象,形成有向图。这些对象描述了文档的结构(页面,元数据,字体和资源)。 * *page content*页面内容,描述了使用一系列操作符将文本和图形放在一个页面上。 -* *file structure*文件结构,包括header(文件头),trailer(文件尾)和交叉引用表,帮助程序找到并读取文件的内容。 +* *file structure*文件结构,包括header(文件头),trailer(文件尾)和交叉引用表,交叉引用表帮助定位并读取文件的内容。 ### Document Content @@ -25,11 +24,11 @@ PDF文件至少包含三种不同的语言: * 整数,如 `50` * 带圆括号的字符串,如 `(The Quick Brown Fox)` * 引用其他对象,如 `2 0 R`,对对象2的引用。 -* 对象的数组(有序集合),如 `[50 30 /Fred]`,是一个包含三个项目的数组,按顺序:`50`, `30` 和 `/Fred`。 +* 对象的数组(有序集合),如 `[50 30 /Fred]`,是一个包含三个元素的数组,按顺序:`50`, `30` 和 `/Fred`。 * 字典(从名称到对象的无序映射),如 `<>`,映射 `/Three` 到 `3` 和 `/Five` 到 `5`。 * stream(流),它由字典和一些二进制数据组成。这些用于存储PDF图形运算符的流,以及其他二进制数据,如图像和字体。 -例如,这是一个页面对象,它是一个包含许多项目的字典,每个与名称相关联: +例如,这是一个页面对象,它是一个包含许多键值对的字典: ``` << /Type /Page /MediaBox [0 0 612 792] @@ -39,7 +38,7 @@ PDF文件至少包含三种不同的语言: >> ``` -这个词典包含五个条目: +这个词典包含五个键值对: `/Type /Page` 名称 `/Page` 与字典键 `/Type` 相关联。 @@ -48,78 +47,75 @@ PDF文件至少包含三种不同的语言: 四个整数 `[0 0 612 792]` 的数组与字典键 `/MediaBox` 相关联。 `/Resources 3 0 R` - 对象编号3与字典键 `/Resources` 相关联。 + 编号3的对象与字典键 `/Resources` 相关联。 `/Parent 1 0 R` - 对象编号1与字典键 `/Parent` 对象相关联。 + 编号1的对象与字典键 `/Parent` 对象相关联。 `/Contents [4 0 R]` 间接引用 `[4 0 R]` 的单元素数组与字典键 `/Contents` 相关联。 ### Page Content -页面内容是运算符列表,每个运算符前面都有零个或多个 -操作数。这是一系列操作符,用于在36号字体选择/F0字体并放置 -当前位置的文字: +页面内容是运算符列表,每个操作符前面都有零个或多个 +操作数。在下面这个例子中,表示选择在36号的/F0字体,并 +当前位置放置文字Hello, World!: ``` /F0 36.0 Tf (Hello, World!) Tj ``` -这里,`Tf` 和 `Tj` 是运算符,而 `/F0`, `36.0` 和 `(Hello, World!)` 是操作数。 -你可以看到一些语法元素(例如,名称和字符串)是共享的跨页面内 -容和文档内容使用的语言。 +在例子中,`Tf` 和 `Tj` 是操作符,而 `/F0`, `36.0` 和 `(Hello, World!)` 是操作数。 +你可以看到一些语法元素(例如,名称和字符串)是共享,在Page Content页面内容和Document Content文档内容中都可以使用。 -### 文件结构 +### File Structure 文件结构包括: -* 用于将文件区分为PDF文档的header(文件头)。 -* 一个交叉引用表,列出了文档中每个对象的字节偏移量 - 这个 -允许任意访问对象,而不是必须按顺序读取。 +* 用于将文件标记为PDF类型的header(文件头)。 +* 一个交叉引用表,列出了文档中每个对象的字节偏移量 - 这 +允许任意访问对象,而不必按顺序读取。 * trailer(文件尾),包括交叉引用表的字节偏移,后跟文件结束标记。 -在编写我们的示例文件时,我们将对许多文件结构使用不完整的值, -依靠*pdftk*来填写细节。例如,我们手动编写交叉引用表是不切实际的。 +在创建pdf示例文件时,我们不需要将所有文件结构保持完整, +而是依靠*pdftk*来补充细节。例如,我们手动编写交叉引用表是不切实际的 +(译者注:如上所述,交叉引用表要记录每个对象在文件中的偏移量)。 ## Document 结构 -我们将要构建的示例只是最简单有意义的PDF文件。然而, -它需要大量的元素。除了我们的文件结构 -如上所述,最小的PDF文档必须包含许多基本部分: +我们将要构建的只是最简单有意义的PDF文件。然而你会看到, +它仍需要大量的元素。除了我们上述描述的文件结构 ,最小的PDF文档必须包含许多基本部分: * trailer字典,提供有关如何阅读其余内容的信息文件中的对象 * 文档目录,它是对象图的根。 * 页面树,它枚举文档中的页面。 * 至少有一页。每个页面必须具有: * - resources(资源),包括例如字体。 - * - 其页面内容,其中包含绘制文本和图形的说明在页面上。 + * - contents(页面内容),其中包含如何在页面中绘制文本和图形的说明在页面上。 -这种安排如图2-1所示。 +这种结构如图2-1所示。 ![](./images/figure%202-1.png) ## 构建元素 我们将PDF数据输入到文本文件中。 -文本编辑器选择的行结尾并不重要(\[在 Unix 和 Mac OS X 中]和 -\\[在 Windows 中]都很好)。 -我们将跳过一些信息(手动难以解决的数据),依靠*pdftk*来填充它。我们会: +文本编辑器选择的行结尾并不重要(在 Unix 和 Mac OS X 中的`CR`和 +在 Windows 中的``。 +我们将跳过一些信息(人工难以介入的工作),依靠*pdftk*来填充它。我们会: * 使用简短的header。 * 跳过了页面内容流的长度,因此我们不必手动计数字节数。 * 省略几乎所有的交叉引用表 -* 使用0表示交叉引用表的字节偏移量,以避免必须计数它手动。 +* 使用0表示交叉引用表的字节偏移量,以避免必须人工计数。 -首先,我们将查看文件的各个部分(按照它们出现的顺序)然后查看 -我们将它们放在一起并运行*pdftk*来制作有效的PDF文件。 +首先,我们将按顺序依次查看文件的各个部分,然后将它们放在一起并运行*pdftk*来制作有效的PDF文件。 ### 文件头 -文件头通常由两行组成。第一行将文件标识为PDF和 -给出它的版本号: +文件头通常由两行组成。第一行将文件标识为PDF并给出它的版本号: ``` %PDF-1.0 % PDF 版本号为 1.0 的文件头 ``` 第二行很难输入文本编辑器,因为它包含不可打印的字符。 -我们将有*pdftk*为我们这样做。 +我们将使用*pdftk*生成第二行内容。 ### 主要对象 -到文件的主体-对象。第一个是Page列表,它是链接到文档中页面对象的字典。 +现在说文件的主体-对象。第一个是Page列表对象,它是链接到文档中页面对象的字典。 ``` 1 0 obj % 对象1 @@ -130,7 +126,7 @@ PDF文件至少包含三种不同的语言: endobj % 对象1结束 ``` -接下来是页面。再次,它是一个字典。它包含纸张大小,间接 +接下来说页面对象。它也是一个字典。它包含纸张大小,间接 引用返回页面列表,以及图形内容和资源。 ``` 2 0 obj @@ -143,7 +139,7 @@ endobj % 对象1结束 endobj ``` -现在,资源(resource)。在这里,只有一个条目,字体字典,在我们的 +现在说资源(resource)对象。在这里,只有一个条目,字体字典,在我们的 示例包含单个字体,我们将使用该字体在页面上写入一些文本。 ``` 3 0 obj @@ -158,14 +154,12 @@ endobj ``` ### 图形内容 -页面内容流包含用于放置文本和图形的一系列运算符 -在页面上。它通过页面字典中的 `/Contents` 条目链接。 +页面内容流包含在页面上放置文本和图形的一系列操作符。它通过页面字典中的 `/Contents` 条目链接。 -流对象由字典后跟原始数据流组成,包含一个 -一系列PDF操作数和运算符。通常,这将被压缩以减少 -文件大小,但我们手动输入,所以我们不压缩它。 -我们还必须以字节为单位指定流的长度-*pdftk*将为我们添加所需的 - `/Length` 条目到流字典。 +流对象由字典以及原始数据流组成,流包含一系列PDF操作数和操作符。 +通常,这部分内容会被压缩以减少文件大小。 +但我们这次是人工输入,所以我们不压缩它。 +我们还必须以字节为单位指定流的长度-*pdftk*将为我们添加所需的`/Length` 条目到流字典。 ``` 4 0 obj % 页面内容流 @@ -180,41 +174,39 @@ endstream % 流结束 endobj ``` -页面上的图形运算符流的结果如图2-2所示。 +页面上的图形操作符流的结果如图2-2所示。 ![](./images/figure%202-2.png) ### 目录,交叉引用表和文件尾 -文件的最后一部分以文档目录开头,该目录是文档目录的根对象 -对象图。接下来是交叉引用表,它给出了字节偏移量 -文件中的每个对象。我们将*pdftk*为我们填写此内容。最后两行:一行 -给出交叉引用表开始的字节偏移量(我们写0和pdftk将 -替换它为我们)。最后,文件结束标记 `%%EOF`。 +文件的最后一部分以Document Catalog文档目录开头,该目录是文档目录的根对象对象图。 +接下来是交叉引用表,它给出了文件中每个对象的字节偏移量。 +我们将使用*pdftk*为我们补充此内容。 +最后两行:一行给出交叉引用表开始的字节偏移量(我们写0,pdftk将替换为真实偏移量)。一行是文件结束标记 `%%EOF`。 ``` 5 0 obj -<< /Type /Catalog % 文件目录 - /Pages 1 0 R % 参考页面列表 +<< /Type /Catalog % 文档目录 + /Pages 1 0 R % 间接引用页面列表对象 >> endobj xref % 我们跳过了交叉引用表的开始 0 6 trailer << /Size 6 % 交叉引用表中的行数(对象数加1) - /Root 5 0 R % 参考文档目录 + /Root 5 0 R % 间接引用文档目录对象 >> startxref 0 % xref表开始的字节偏移量,我们将其设置为0 %%EOF % 文件结束标记 ``` -现在我们准备将这些部分放在一起了 - +现在我们准备将这些部分放在一起了。 ## 把它放在一起 可以在此在线资源中找到书此文件的源(示例2-1), 或者你可以自己输入。将其保存为*hello-broken.pdf*。 -例2-1。无效的hello-broken.pdf PDF文件适合手动创建 +例2-1。无效的hello-broken.pdf PDF文件,适合手动创建 ``` %PDF-1.0 % 文件header @@ -267,8 +259,7 @@ startxref %%EOF ``` -就目前而言,hello-broken.pdf不是有效的PDF文件,甚至也不是Adobe Reader(其中 -相当容忍格式错误的文件)将无法应对。 +就目前而言,hello-broken.pdf不是有效的PDF文件,甚至也不是Adobe Reader(虽然它能处理很多文件的格式错误)将无法应对。 > 译注: > Adobe Acrobat 2018 已经可以直接打开 `hello-broken.pdf` 文件。 @@ -281,9 +272,8 @@ startxref **pdftk hello-broken.pdf output hello.pdf** -*pdftk*读取文件及其对象,并为缺失或计算正确的数据 -我们写的错误部分,并生成示例2-2中显示的有效文件。注意 -一些语法的间距和格式已经改变 - 每个PDF制做人对此有不同的选择。 +*pdftk*读取文件及其对象,并更正缺失或我们写错的部分,生成示例2-2中显示的有效文件。 +注意一些语法的间距和格式已经改变 - 每个PDF创建软件对此有不同的选择。 *例2-2。完成的PDF文件hello.pdf,由pdftk修复* ``` @@ -357,11 +347,11 @@ startxref ``` 1: 一些不可打印的字符已添加到PDF标题中 - 这可确保文件被识别为二进制 -(而不是文本),例如,通过FTP等文件传输程序。 +(而不是文本)格式,例如,通过FTP等文件传输程序。 2: 已填写流的字节长度。 -3: 交叉引用表已填入了每个对象的字节偏移量文件。 +3: 交叉引用表已填入了每个对象的字节偏移量。 4: 已填写交叉引用表开头的字节偏移量。 @@ -371,8 +361,8 @@ startxref ## 备注 -我们已经看到了如何从头开始构建一个简单的PDF文件,使用*pdftk*来帮助我们,以及 -我们已经看了一些构成PDF文档的基本语法。 +我们已经看到了如何从头开始构建一个简单的PDF文件,然后使用*pdftk*来帮助我们, +在这个过程中我们看了一些构成PDF文档的基本语法。 你也可以使用文本编辑器查看现有的PDF文件。但是,有些 数据(例如构成页面内容的图形运算符)很可能被压缩,因此不可读。 diff --git a/chapter3.md b/chapter3.md index 1544ba7..eba97e6 100644 --- a/chapter3.md +++ b/chapter3.md @@ -1,11 +1,11 @@ # 第3章 - 文件结构 -在本章中,我们将描述PDF文件的四个主要部分的布局和内容, +在本章中,我们将介绍PDF文件四个主要部分的布局和内容, 以及构成每个部分的对象的语法。我们还概述了将PDF文件读入 高级数据结构的过程,以及将该结构写入PDF文件的相反操作。 ## File 布局 -一个简单有效的PDF文件按顺序包含四个部分: +一个简单有效的PDF文件包含四个部分,按顺序依次为: 1. *header*,提供PDF版本号 1. *body* 包含页面,图形内容和大部分辅助信息的主体,全部编码为一系列对象。 1. 交叉引用表,列出文件中每个对象的位置便于随机访问。 @@ -76,7 +76,7 @@ xref % 交叉引用表从这里开始 0000000192 00000 n 0000000291 00000 n 0000000409 00000 n -trailer % 预览块从这里开始 +trailer % trailer从这里开始 << /Root 5 0 R /Size 6 @@ -95,19 +95,19 @@ PDF文档是在文件中创建PDF对象的图形的过程。这个 ![图 3-1](./images/figure%203-1.png) -我们现在依次仔细研究这四个部分中的每一个,使用例3-1作为参考。 +我们现在轮流研究这四个部分中的每一个,使用例3-1作为参考。 ### 文件头 PDF文件的第一行给出文档的版本号。在我们的示例中,是: ``` %PDF-1.0 ``` -这将文件定义为PDF版本1.0。PDF是向后兼容的,因此PDF 1.3文档 -应该由知道例如PDF 1.5的程序读取。它在很大程度上也是向前兼容的, -因此大多数PDF程序都会尝试读取任何文件,无论假设的版本号是什么。 +这将文件定义为PDF版本1.0。PDF是向后兼容的,因此PDF 1.3的文档 +应该由可以解析——例如PDF 1.5——的程序读取。它在很大程度上也是向前兼容的, +因此大多数PDF程序都会尝试读取任何文件,无论文件的版本号是什么。 由于PDF文件几乎总是包含二进制数据,因此如果更改行结尾 -(例如,如果文件通过FTP以文本模式传输),它们可能会损坏。 +(例如文件通过FTP以文本模式传输),它们可能会损坏。 为了允许传统文件传输程序确定文件是二进制文件, 通常在标头中包含一些字符代码高于127的字节。例如: ``` @@ -121,8 +121,8 @@ PDF文件的第一行给出文档的版本号。在我们的示例中,是: ``` ### Body -文件正文由一系列对象组成,每个对象前会有单独的一行,该行包括一个对象编号,一个世代号以及关键字obj。 -紧跟在对象之后的是endobj关键字,它同样独占一行。例如: +Body由一系列对象组成,每个对象前会有单独的一行,包括一个对象编号,一个世代号以及关键字obj。 +最后以关键字endobj结束,它同样独占一行。例如: ``` 1 0 obj << @@ -132,21 +132,21 @@ PDF文件的第一行给出文档的版本号。在我们的示例中,是: >> endobj ``` -这里,对象编号是1,并且世代号是0(它几乎总是)。 +这里,对象编号是1,并且世代号是0(它几乎总是0)。 对象1的内容位于1 0 obj和endobj两行之间。 -在这种情况下,它是字典`<>` +在上面的例子中,它是字典`<>` ### 交叉引用表 交叉引用表列出了文件正文中每个对象的字节偏移量。 -这允许随机访问对象,因此不必按顺序读取它们和对象 -永远不会阅读从未使用过的。这尤其意味着,即使在大型文件上, -像计算PDF文档中的页数这样的简单操作也可以很快。 +这提供了随机访问对象的能力,因此解析pdf文件时不需要从头到尾读取所有对象,而且没有用到的对象就不必读取。 +这意味着,即使对于大型PDF文档来说, +像计算文档中页数这样的简单操作也可以很快。 PDF文件中的每个对象都有一个对象编号和一个世代编号。 -当重用交叉引用表条目时使用世代号 - 我们在这里不考虑它们(它们将始终为零)。 +当重用交叉引用表条目时使用世代号 - 我们在这里不考虑它们(它们将始终为0)。 -出于我们的目的,我们可以认为交叉引用表由一个表示条目数的标题行组成, -然后是一个特殊条目,然后是文件体中每个对象的一行。在我们的文件中: +交叉引用表由一个表示条目数的标题行组成, +接下来是一个特殊条目,然后是文件中每个对象表示为一个条目。在我们的文件中: ``` 0 6 % 表中的六个条目,从0开始 0000000000 65535 f % 特别条目 @@ -156,22 +156,22 @@ PDF文件中的每个对象都有一个对象编号和一个世代编号。 0000000291 00000 n 0000000409 00000 n % 对象5的字节偏移量为409 ``` -请注意,字节偏移量以前导零存储,以确保每个条目都相同 -长度。因此,我们也可以通过随机访问来读取交叉引用表。 +请注意,字节偏移量以前导零存储,以确保每个条目都有相同的 +长度。因此,我们也可以通过随机访问来读取交叉引用表中的条目(译者注:类似于通过数组索引访问数组元素)。 ### 文件尾 Trailer的第一行只是Trailer关键字。之后是Trailer -字典,至少包含/Size 条目(给出条目数在交叉引用表中)和 -/Root条目(它给出了对象编号)文档目录,它是正文中对象图的根元素。 +字典,至少包含/Size 键值对(表示交叉引用表中的条目数)和 +/Root键值对(它给出了Catalog对象编号,它是Body中对象图的根元素)。 接下来是一行只包含startxref关键字, 一行包含一个数字(文件中交叉引用表开头的字节偏移量), -然后是行\%\%EOF,它表示PDF文件的结尾。 +然后是行%%EOF,它表示PDF文件的结尾。 这是示例3-1中的Trailer: ``` -trailer % 预览块关键字 -<< % 预览块字典 +trailer % Trailer关键字 +<< % Trailer字典 /Root 5 0 R /Size 6 >> @@ -201,38 +201,38 @@ PDF文件是8位字节的序列。使用我们在本章中描述的规则, |13|Carriage return| |32|Space| -PDF文件可以使用\,\或\\序列来结束一行。 -但请注意,一起更改行结尾(例如,在文本编辑器中)可能会破坏文件, +PDF文件可以使用``,``或``序列来结束一行。 +但请注意,更改行结尾(例如,在文本编辑器中)可能会破坏文件, 因为它将改变在压缩二进制数据部分中发生的任何行结束序列。 ## 对象 PDF支持五个基本对象: * 整数和实数,例如42和3.1415 * 字符串,括在括号中,并有各种编码。例如 `(The Quick Brown Fox)`。 -* 名称,用于词典中的键,以及无数其他用途。它们带有/,例如/Blue。 +* 名称,一般用于词典中的键,当然还有很多其他用途。它们带有/,例如/Blue。 * 布尔值,由关键字true和false表示。 * null对象,由关键字null表示。 和三个复合对象: * 数组,包含其他对象的有序集合,如`[1 0 0 0]`。 -* 字典,由无序的对集合组成,将名称映射到对象。 +* 字典,由无序的键值对集合组成,将名称映射到对象。 例如,`<>`, 其将/Contents映射到间接引用4 0 R和/Resources到间接引用5 0 R. -* 包含二进制数据的流以及描述数据属性的字典, -例如其长度和任何压缩参数。流用于存储图像,字体等。 +* 流,包含二进制数据流以及描述数据属性的字典, +例如其长度和可能存在的压缩参数。流用于存储图像,字体等。 + 以及将对象链接在一起的方法: * 间接引用,它形成从一个对象到另一个对象的链接 PDF文件由对象图组成,间接引用形成它们之间的链接。例3-1的对象图如图3-1所示。 ### 整数和实数 -整数写为一个或多个十进制数字0..9,可选地以加号或减号开头: +整数写为一个或多个十进制数字0..9,可以前置加号和减号: ``` 0 +1 -1 63 ``` -实数被写为一个或多个十进制数字,可选地前面带有加号或减号, -并且可选地有一个小数点,可以是内部, -或以下: +实数被写为一个或多个十进制数字,中间可以添加一个小数点,同样的,可以前置加号和减号, +比如: ``` 0.0 0. .0 -0.004 65.4 ``` @@ -243,7 +243,7 @@ PDF文件由对象图组成,间接引用形成它们之间的链接。例3-1 ### 字符串 字符串由一系列字节组成,写在括号之间: `(Hello, World!)` -反斜杠\字符和括号字符()必须通过在它们前面加上反斜杠进行转义。例如,写作: +若字符串本身包含反斜杠\字符和括号字符(),必须在它们前面加上反斜杠\进行转义。例如: `(Some \\ escaped \(characters)` 表示字符串"Some \ escaped (characters)"。外部存在已经平衡的括号对 在字符串内不需要转义。例如`(Red(Rouge))`表示字符串“Red(Rouge)”。 @@ -263,17 +263,17 @@ PDF文件由对象图组成,间接引用形成它们之间的链接。例3-1 #### 十六进制字符串 -字符串也可以写为\<和\>之间的十六进制数字序列,每对代表一个字节: +字符串也可以写为<和>之间的十六进制数字序列,每对代表一个字节: ``` <4F6Eff00> Bytes 0x4F, 0x6E, 0xFF, and 0x00 ``` -当存在奇数个数字时,假设最后一个为十六进制字符串通常用于使二进制数据用户可读。 -它在功能上与以通常方式描述字符串相同。 +当存在奇数个数字时,假设最后一个十六进制数字为0。十六进制字符串通常用于使二进制数据用户可读。 +它在功能上与以普通字符串相同。 ### 名称 -名称在整个PDF中使用,作为字典的键和定义各种多值对象, -其中使用整数枚举它们将是不直观的。一个名称 -引入正斜杠。例如: +名称存在于整个PDF中,它可以作为字典的键以及定义各种多值对象, +因为使用对象号枚举对象们是不直观的。一个名称 +以正斜杠开头。例如: ``` /French ``` @@ -287,28 +287,28 @@ PDF文件由对象图组成,间接引用形成它们之间的链接。例3-1 十六进制20是空格的代码。名称区分大小写(/French和/french不同)。 ### 布尔值 -PDF允许布尔值为true和false。它们经常在字典条目中用作标志。 +PDF中的布尔值为true和false。它们经常在字典条目中用作标志。 ### 数组 -数组表示PDF对象的有序集合,包括其他数组。对象不一定都是同一类型。例如,数组: +数组表示PDF对象的有序集合,可以内嵌其他数组。数组元素不必是同一类型。例如: ``` [0 0 400 500] ``` -按顺序包含四个数字:0,0,400,500。数组: +按顺序包含四个数字:0,0,400,500。再例如: ``` [/Green /Blue [/Red /Yellow]] ``` -包含三个项目:名称/Green,名称/Blue和两个名称的数组[/Red /Yellow]. +包含三个项目:名称/Green,名称/Blue和拥有两个名称元素的数组[/Red /Yellow]. ### 字典 字典表示键值对的无序集合。字典将键映射到值 - 提供键, 值是在字典中查找的结果。键是名称,值可以是任何PDF对象。 -字典写在\<\<和\>\>之间。例如: +字典写在<<和>>之间。例如: ``` <> ``` 将名称/One映射到整数1,将名称/Two映射到整数2, -将名称/Three映射到整数3.字典当然可以包含其他字典。 +将名称/Three映射到整数3。字典当然可以内嵌其他字典。 嵌套字典构成了大多数PDF文件中的大部分非图形结构化数据。 ### 间接引用 @@ -317,7 +317,7 @@ PDF允许布尔值为true和false。它们经常在字典条目中用作标志 ``` 6 0 R ``` -这里,6是对象编号,0是世代号(这里我们不考虑),R是间接参考关键字。 +这里,6是对象编号,0是世代号(这里我们不考虑),R是间接引用关键字。 例如,这是使用间接引用的典型字典: ``` @@ -326,7 +326,6 @@ PDF允许布尔值为true和false。它们经常在字典条目中用作标志 ``` 在此示例中,对象10和4在字典的值中被引用。 - ## 流和过滤器 流用于存储二进制数据。它们由字典和一大块二进制数据组成。 字典根据流所放置的特定用途列出数据的长度,以及可选的其他参数。 @@ -340,7 +339,7 @@ PDF允许布尔值为true和false。它们经常在字典条目中用作标志 /Length 65 % 数据长度 >> stream % 流关键字 -1. 0. 0. 1. 50. 700. cm % 65字节的数据,这里是图形流 +1. 0. 0. 1. 50. 700. cm % 65字节的数据,这是图形流 BT /F0 36. Tf (Hello, World!) Tj @@ -368,7 +367,7 @@ endobj % 对象的结束 ``` 796 0 obj <> % 流 -HTKO0÷ü % 这里还有 268 字节被隐藏,即总计 275 字节 +HTKO0÷ü % 这里还有 268 字节被省略 endstream endobj ``` @@ -379,12 +378,11 @@ endobj 需要外部参数的过滤器(例如,在数据流本身之外定义压缩参数)也会将这些参数存储在流字典中。 - ## Incremental Update 增量更新 增量更新允许通过将修改附加到文件末尾来更新文件, 因此不需要再次写入整个文件(对于大文件,可能需要很长时间)。 -更新构成新的或更改的对象,以及对交叉引用表的更新。 -这意味着保存更改所花费的时间更少,但文件可能会变得臃肿(因为不再需要的对象无法删除)。 +更新操作对应新建/修改对象,以及更新交叉引用表。 +这意味着保存更新操作所花费的时间更少,但文件可能会变得臃肿(因为不再需要的对象无法删除)。 此更新过程可能会发生多次。副作用是以这种方式更新的 文件可能会使这些更改撤消一个或多个级别,以检索文档的早期版本。 @@ -416,9 +414,9 @@ endobj 在网络环境中查看大型PDF文件时,尤其是当数据速率较低或网络延迟较高时, 用户不希望等待整个文件下载以查看它。在Web浏览器中查看文档时,这一点尤为重要。 -我们希望第一页快速显示,并且要更改为另一页(通过单击超链接或书签)尽可能快。 -在个人的情况下页面大(而不仅仅是整个文档),我们应该首先看页面内容是增量, -最重要的内容。网络传输机制例如HTTP(超文本传输协议,用于在Web浏览器中获取网页) +我们希望第一页快速显示,并且跳转到另一页(通过单击超链接或书签)也要尽可能快。 +在个别页面特别大(而不仅仅是整个文档)的情况,我们期望能够实现重要内容先展示的懒加载。 +网络传输机制例如HTTP(超文本传输协议,用于在Web浏览器中获取网页) 通常允许获取任意数据块。但是,因为延迟,我们希望获取一个包含页面所有数据的块, 而不是数百个小块,每个对象一个。 @@ -449,12 +447,12 @@ GhostScript附带的*pdfopt*命令行程序可以线性化文件。例如: 这会使input.pdf线性化并将结果写入output.pdf。 ## 如何读取PDF文件 -要读取PDF文件,将其从一系列平坦的字节转换为内存中对象的图形, -通常可能会发生以下步骤: +要读取PDF文件,将其从字节序列转换为内存中对象的图形, +通常包含以下步骤: 1. 从文件开头读取PDF header,确认这确实是PDF文档并检索其版本号。 1. 现在通过从末尾向后搜索找到文件结束标记 文件。现在可以读取trailer字典,以及开头的字节偏移量检索交叉引用表。 -1. 现在可以读取交叉引用表。我们现在知道每个对象在哪里了文件是。 +1. 现在可以读取交叉引用表。我们现在知道每个对象在文件中的位置。 1. 在此阶段,可以读取和解析所有对象,或者我们可以离开此过程 直到实际需要每个对象,按需阅读。 1. 我们现在可以使用数据,提取页面,解析图形内容,提取元数据等。 @@ -483,13 +481,13 @@ Dictionary 本章前面的图3-1显示了例3-1中文件的对象图。 ## 如何编写PDF文件 -将PDF文档写入文件中的一系列字节要比阅读它简单得多, +将PDF文档以字节序列的方式写入文件要比解析它简单得多, 我们不需要支持所有PDF格式,只需要支持我们打算使用的子集。写作 PDF文件非常快,因为它只是将对象图展平为一系列字节。 1. 输出header。 -1. 删除PDF中任何其他对象未引用的任何对象。这个避免编写不再需要的对象。 -1. 重新编号对象,使它们从1到n运行,其中n是对象的数量文件。 -1. 逐个输出对象,从对象编号1开始,记录字节交叉引用表的每个偏移量。 +1. 删除PDF中未被使用到的对象。这个避免写入不再需要的对象。 +1. 重新编号对象,使它们从1到n运行,其中n是对象的总数。 +1. 逐个输出对象,从对象编号1开始,记录每个对象在文件中的偏移量,用于交叉引用表。 1. 编写交叉引用表。 1. 编写trailer,trailer字典和文件结束标记