为什么将 PDF 转换为纯文本如此困难?

Why is it so hard to convert PDF to plain text?

我需要将一些 PDF 转换回文本。我尝试了很多软件和在线工具,结果总是很一般。

为什么技术上这么难?

我们不要假设您谈论的是仅包含一些位图图像的 PDF,因为应该清楚,在这种情况下您只能求助于具有所有限制的 OCR。

让我们假设文本是在手头的 PDF 中绘制的。

在 PDF 页面上绘制的内容由该页面内容流中 说明 序列 决定。 "Text is drawn" 在页面上意味着在这些指令中有一些设置字体以供后续指令使用,一些设置文本位置和方向以供后续指令使用,还有一些实际绘制由 "string arguments".

文本提取是从内容流中获取指令序列的任务,而不是绘制字体和位置设置指令指示的文本,将其导出到使用标准编码的明智顺序,通常是所用编程语言/平台的字符类型的编码。

第一个问题是理解那些文本绘制指令的字符串参数的编码:

  • 每种字体都可以有自己的编码;要提取文本,除了绘制文本和连接字符串内容的说明之外,不能简单地忽略所有内容,您始终必须考虑当前字体(一些极其简单的文本提取器会忽略这一点,因此经常失败 return 一些明智的事情);

  • 有大量预定义的编码,有些让您想起您知道的编码,例如WinAnsiEncoding,很多你可能不知道,例如添加-RKSJ-H;这些编码可以使用每个字形的恒定字节数,或者它们可以是混合多字节;所以文本提取器必须支持非常多的编码才能开始;

  • 编码也可能完全是临时的和任意的;特别是在嵌入子集字体的情况下,人们经常看到通过在需要时从某个起始值处理字符代码生成的临时编码;即页面上使用的给定字体中的第一个字形被赋予起始值作为代码,下一个不同的字形被赋予起始值加一,下一个不同的字形的起始值加二,等等; "Hello World" 和起始值为 48(ASCII 值为“0”)将导致“01223453627”;这些字体可能包含到 Unicode 的映射,但它们不是必需的。

下一个问题是理解字符串的顺序:

  • 字符串绘制指令可能以任意顺序出现,例如 "Hello" 可能首先绘制 "lo",然后在移回 "el" 之后,然后再次绘制向后移动 "H";要提取文本不能忽略文本定位指令并简单地连接文本字符串,您始终必须考虑当前位置(一些简单的文本提取器会忽略这一点,因此可能无法 return 一些明智的事情);

  • 多栏文本可能会出现困难,文本可能会逐行绘制,例如首先是第一列顶行的文本,然后是第二列顶行的文本,然后是第一列的第二行,然后是第二列的第二行,依此类推; PDF 中不需要任何提示文本是多栏的。

另一个问题是识别格式或样式工件:

    单词之间的
  • space不需要画一个space字形,也可以通过文本位置改变指令来实现;不尝试识别由文本定位指令创建的间隙的文本提取器可能 return 没有 spaces 的结果;另一方面,可以使用相同的技术以最佳距离绘制相邻字形,也称为字距调整;试图识别由文本定位指令创建的间隙的文本提取器可能会在应该 none;

  • 的地方错误地 return spaces
  • 有时会打印选定的单词以作额外强调;在提取的文本中,这些间隙可能显示为 space 个字符,文本的自动后处理可能将其视为单词分隔符;

  • 通常对于粗体文本,使用不同的粗体字体程序;如果手头没有,人们有时会发挥创造力,通过将相同的文本打印两次并使用微小的偏移来模仿粗体;使用稍大的偏移量(或不同的变换)和不同的颜色,可以模拟阴影效果;如果文本提取器不尝试识别这一点,您最终会在输出中包含一些重复字符。

额外信息不完整或错误导致更多问题:

  • ToUnicode 字体映射(从字符代码到 Unicode 的可选映射)可能不完整或包含错误;那里,例如这里有很多关于堆栈溢出的问题,处理不正确的 ToUnicode 印度文字地图;文本提取结果反映了这些错误;

  • 甚至有包含矛盾信息的 PDF,例如ToUnicode 映射中有错误,但 ActualText 条目中的信息正确;这被一些 PDF 创建者用来允许从某些程序中正确复制和粘贴(在这种情况下更喜欢 ActualText 条目),同时在其他程序的输出中注入错误(更喜欢 ToUnicode 信息然后).

如果您希望文本提取器仅提取最终在页面中可见的文本,则会出现另一个问题:

  • 文本可能绘制在当前裁剪区域或可见页面区域之外;文本提取器需要牢记这些;

  • 文本可以使用渲染模式绘制"invisible";文本提取器必须关注渲染模式;

  • 可以使用与背景相同的颜色绘制文本;要认识到这一点,文本提取器不仅可以查看当前指令和一些图形状态细节,还必须考虑在文本位置预先绘制的任何内容;

  • 文本可以绘制为剪辑路径;要识别此文本最终是否可见,只要剪辑路径处于活动状态,文本提取器就必须跟踪文本区域中绘制的内容;

  • 文本稍后可能会被其他内容覆盖;在这种情况下,文本提取器必须删除已识别的文本;但是根据混合模式和透明度设置,这些覆盖物可能会或可能不会让文本闪耀;因此,为了获得正确的结果,文本提取器必须为每个字形跟踪其绘制的颜色、背景的颜色,以及之后所有这些漂亮的效果对这些颜色的作用;当然,字形颜色和背景颜色都可能很有趣,例如一些阴影颜色;并且涉及的颜色space可能不同,需要在颜色space之间来回转换;等等。

此外,可能会在文本提取器通常不会看的地方绘制文本:

  • 一些工具通过将文本放入一个模式并用该模式填充页面区域来隐藏文本提取;
  • 同样有3种字体; type 3 字体中的每个字符都由其自己的内容流表示;因此,工具可以绘制单个 type 3 字体字形的内容流中的所有文本,然后在页面上绘制该字形。

...

同时您肯定已经知道为什么文本提取结果可能不尽如人意。请放心,上面的列表并不完整,文本提取还有更多的复杂性。