我需要从 pdf 流中提取一些信息。
提取相关文本非常简单,因为它类似于:
BT /Fo0 7.20 Tf 67.81 569.38 Td 0.000 Tc (TOTAL AMOUNT) Tj ET
我可以考虑固定 y 位置,而 x 位置由于 giustification 是可变的。但我的问题是识别页面的开头和结尾。
您不应该确定您使用“信息提取器”遇到的所有 PDF 都表现得很好。或者你可以,因为你知道他们是?
否则,很可能您遇到的 PDF 代码如下所示:
BT
/Fo0 7.20 Tf
67.81 569.38 Td
0.000 Tc
(TO)12(T)13(AL A)11(M)14(OUNT) TJ
ET
那是, ...
TJ
而不是Tj
, 以允许单独的字形定位,为了可靠地获取页面的文本内容,您必须解析 PDF 的结构,简而言之:
/Type /Page
;的所有对象/Contents
;
/Contents
单个流,或/Contents
可能指向一个流数组;实际上,上述步骤中的第一步可能会变得更复杂一些:
trailer <<...>>
部分/Root
对象的信息/Pages
从/Root
对象中提取有关 的信息/Pages
的中间页面树节点;/Kids
通过检查对象找到此页面树节点的所有后代/Kids
;
/Type /Pages
(在这种情况下,它是另一个页面树节点,而不是树叶,您必须进一步沿着树向下);/Type Page
(在这种情况下,你到达了一个页面树叶,这意味着你真的到达了一个页面)。在这一点上,我应该注意,您在此旅程之后找到的第一页是第 1 页。接下来是第 2 页,依此类推。请注意,没有任何页面有任何元数据说“我是第 N 页”——这完全取决于按照您解析从根对象开始的页面树的顺序。
现在您确实找到了内容流,您还面临两个问题:
您正在查找的内容流可能根本不是明文(如您的代码所示)。内容流经常被一种允许的压缩方案压缩,您必须先扩展它们,然后才能解析文本内容。
要查看流是否被压缩,请注意相应的*Decode关键字(经常显示为 /Filter /FlateDecode
)。
成功解压缩页面的内容流后,您可能会遇到描述文本的完全不直观的字符代码。它可能与您想象的和示例代码中显示的行为良好的 ASCII 类型完全不同。
您必须查找字体(甚至像 CID 这样的多字节字体)、它们的编码、CMap 等等。
除非,正如我在第一句话中所质疑的那样,您知道在您的特定用例中不会发生这种情况......