PDF 格式

建议查阅 PDF 规范 来获取详细信息和进一步澄清。

以下内容仅为该格式的大致概述


整体结构

一个 PDF 文件包括:

  1. 头部 (Header):包含 PDF 的版本,例如 %PDF-1.7

  2. 主体 (Body):包含一系列间接对象 (indirect objects)

  3. 交叉引用表 (xref):包含主体中间接对象的列表

  4. 尾部 (Trailer)


交叉引用表 (xref)

交叉引用表是主体中间接对象的一个索引表,它通过指向文件中的具体位置,实现对对象的快速访问。

其结构如下:

xref 42 5
0000001000 65535 f
0000001234 00000 n
0000001987 00000 n
0000011987 00000 n
0000031987 00000 n

逐行解析:

  • xref:标识交叉引用表的开始。

  • 42:当前 xref 部分中第一个对象的编号;5 表示 xref 表中条目的总数。

  • 每个对象条目格式为 nnnnnnnnnn ggggg n

    • nnnnnnnnnn:对象的字节偏移量,指出对象在文件中的位置。

    • ggggg:对象的生成号,表示对象的版本历史。

    • n 表示该对象为正常使用对象f 表示该对象为空闲对象

      • 第一个空闲对象的生成号始终为 65535,它是所有空闲对象链表的头部。

      • 正常对象的生成号始终为 0。生成号允许 PDF 文件包含同一对象的多个版本,用于版本控制机制。


主体 (Body)

主体由一系列间接对象组成,格式如下:

counter generation_number << the_object >> endobj
  • counter (整数):对象的唯一标识符。

  • generation_number (整数):对象的生成号。

  • the_object:对象本身,可以为空。以 /Keyword 开头,指定对象类型。

  • endobj:标识对象的结束。

示例(摘自 test_reader.py::test_get_images_raw):

1 0 obj << /Count 1 /Kids [4 0 R] /Type /Pages >> endobj
2 0 obj << >> endobj
3 0 obj << >> endobj
4 0 obj << /Contents 3 0 R /CropBox [0.0 0.0 2550.0 3508.0]
 /MediaBox [0.0 0.0 2550.0 3508.0] /Parent 1 0 R
 /Resources << /Font << >> >>
 /Rotate 0 /Type /Page >> endobj
5 0 obj << /Pages 1 0 R /Type /Catalog >> endobj

尾部 (Trailer)

尾部的格式如下:

trailer << /Root 5 0 R
           /Size 6
        >>
startxref 1234
%%EOF

逐行解析:

  • trailer <<:标识尾部字典的开始,以 >> 结束。

  • startxref:一个关键字,后面跟随 xref 关键字的字节位置。由于尾部始终位于文件末尾,这使得读取器可以快速定位到 xref 表。

  • %%EOF:文件结束标识。

尾部字典是一个键值对列表。键的定义见 PDF 参考规范 1.7 的表 15,例如 /Root/Size(这两个键是必须的):

  • /Root(字典):包含文档目录。

    • 5:目录字典的对象编号。

    • 0:目录字典的生成号。

    • R:表示该对象是对目录字典的引用。

  • /Size(整数):表示 xref 表中的条目总数。


读取 PDF 文件

大多数 PDF 文件是经过压缩的。如果要读取它们,首先需要解压:

pdftk crazyones.pdf output crazyones-uncomp.pdf uncompress

然后将 crazyones-uncomp.pdf 重命名为 crazyones-uncomp.txt,并在你喜欢的 IDE 或文本编辑器中打开它。