概述

  • 由于公司项目中需要针对 Microsoft 的 6 种格式(doc,xls,ppt,docx,xlsx,pptx)以及 pdf 中的文本进行提取以及后续的编辑操作,所以就需要对这些文件的格式能够庖丁解牛才行。而我分配到的是 PDF 这块的工作,相对其他几种格式来说,pdf 的格式相对简单清晰些,再结合一些开源库的实现,目前基本把文本提取的步骤和过程了解的比较清楚了。

PDF 格式解析

  • 从物理结构来说,pdf 内容包括 head, body, crossxref, trailer 四个部分。head 包含的是 pdf 文件的版本号信息,body 则是 pdf 的主体内容,由各个对象(object)组成,crossxref 则是交叉引用表,里面表示的内容是各个对象以及每个对象在文件中的偏移,最后 trailer 表示的 pdf 文件的入口,也就是解析的起点。
  • 从逻辑结构来说,pdf 则是一个树形结构,这样也便于我们进行递归解析。具体的结构可以参看这里
  • pdf 是由一个个对象组成的,主要对象有 dictionary, array, string, boolean, number, stream 以及特有的对象类型 indirect, indirect 对象其实就是间接引用对象,一旦需要解析间接引用,文件的偏移就会反复在文件内游动。从 root 对象一直往下递归解析就可以将整个 pdf 解析完全,不过针对文本提取不需要解析到最底层。

PDF 文本提取

  • 实际上,pdf 由多个 page 组成,而每个 page 包含 pageResource,pageResource 下面包含 Contents 以及 Font,通过 Contents 可以提取到字节流,而通过 Font 可以提取到文本的格式以及编码信息(font encoding)。一般情况下,如果 font 包含 ToUnicode,则直接通过 ToUnicode 进行映射查找;否则如果 font 不是 Type0(Type0 是 composite font,其他的几种 font 则是 simple font),则通过预定义的 simple encoding(例如 WinAnsiEncodingUtf8 等) 以及 differences 数组来获取;否则如果是 font0 并且是属于几十种 Adobe 定义的 encoding 之一的话,则通过 Register-Ordering-UCS 来进行最后的映射获取。