Command Palette

Search for a command to run...

PDF 中的回归是文本,而不是布局

PDF 中的回归是文本,而不是布局

T
Toolz Team
|Oct 21, 2026|18 最小读数
Google 上的首选 Toolz.dev

PDF 工具集合的一部分

PDF to Word

Turn a PDF into an editable .docx in your browser. The text comes back as paragraphs you can edit in Word, Pages, LibreOffice or Google Docs. Nothing is uploaded.

用PDF to Word

我将两页报告转换为 Word 以检查某些内容,第二段如下:

第三位员工收入增长了四分之一,两季度均为支撑。 招聘大额续订计划在 8 月第四季度签署。 保证金持平。 六个角色不变。

两列完全普通的散文,逐行地跨越排水沟,因此每个句子都拼接到旁边的一列中。 没有任何东西被打破。 转换器完全完成了转换器可以做的事情,而这与短语“PDF 到 Word”之间的差距是本指南的整个主题。 下面引用的每个输出来自运行转换,而不是描述它。

TL;博士: PDF 存储坐标字形。 它不存储段落、列、表或标题,因此转换器必须从位置推断它们,并且其中一些推理在您可以预测的方式上是错误的。 按测试报告测量:两列交错线,四行表平整到一行,读“区域 Q2 Q3 EMEA 412 455 Amer 388 401 APAC 120 166”,一个标题合并到它下面的段落中,一个没有文本层的页面根本没有产生任何文本。 您可靠地获得的是可编辑的散文,按页面顺序进行,这对于大多数工作来说都是您想要的。 那个 PDF 到字转换器 是在浏览器中做的,所以文档没有上传。

PDF 中存储的是什么?

绘制页面的说明,而不是文档。

PDF 的内容流表示“将此字体设置为此大小的字体,移动到 x 60,y 720,显示这些字形”。 那个 规格本身 是对绘画模型的描述,文本操作符与绘制线条和填充形状的操作符并列。 文件中没有任何对象表示“段落”,没有表示“这是表”的对象,也没有任何记录两个文本块是列而不是一宽的文本的对象。 格式是设计成一个页面在任何地方都相同的打印,它通过将页面描述为标记而不是内容来实现这一点。

因此,转换器接收定位运行的列表。 pdf。js,它运行的解析器,完全按照页面绘制的方式交还它们。 在测试文件中,第一页产生了其中的 34 个,第二页产生了 4 个。 每次运行都是一个字符串,带有一个 X、一个 Y、一个宽度和一个字体高度,它们到达的顺序是页面绘制的顺序,这不一定是你阅读它们的顺序。

Word 文档需要的所有内容都不需要 PDF,转换器必须从这四个数字中重建。 重建是接下来的全部内容,包括任何地方出错。

转换器如何从坐标中重建段落?

两次通过,每个通道都有一个阈值。

第一个通道组按基线运行:y 值位于彼此的半个字体高度内的运行是一行。 第二个将线条按它们之间的垂直间隙分组。 大于约1.45倍的间距开始新段落,其中“通常”是该页面上的中值间隙而不是固定的数字,因此该规则适用于以9点或14点设置的文档。

一条线内有第三个阈值。 PDF.js 经常在几个运行中分割一个单词,它们之间没有间隙,因此在空格上连接运行将“文件名”变成“f i l e n a m e”。 修复是仅在水平间隙超过字体高度的四分之一时插入一个空格,这大约是一个真实的字体空间的宽度。

这三个数字几乎决定了输出的一切。 当结果好时,他们是对的。 当一个标题坚持下段的段落时,差距低于中位数的 1.45 倍,规则说的是一个段落。

为什么两列交错?

因为列的唯一证据是水平间隙,线分组首先查看垂直位置。

我的测试页面中的两个块位于 x 60 和 x 320 处,它们的线条位于共享基线上。 分组看到六个基线,每个基线都从两边携带文本,并阅读每个基线。 结果是本指南顶部的段落:左列的每一行紧跟着它旁边的行。

这与 OCR 中的加扰列相同,它具有相同的根源:阅读顺序是对由几何组成的布局的判断,由无法读取的东西制成。

处理列的转换器 先执行页面分割步骤,寻找运行页面高度的一致的垂直空白带,并在任何行分组之前将页面分割在那里。 这适用于报纸或期刊报纸,其中阴沟宽而规则。 在侧边栏、拉引号或两列表中断带的常见情况下,它不太可靠。

如果您的文档有列,实际答案是检查输出并修复每页的第一段,或者在文档足够长的情况下一次转换列。

桌子会发生什么?

它变成了一个句子。

我的测试文件有一个四行表,三列。 这是转换后的全部内容:

Region Q2 Q3 EMEA 412 455 AMER 388 401 APAC 120 166

每一个价值都幸存下来。 结构没有。 你不能从那条线上看出 412 是 EMEA 的 Q2 数字,而不计算位置和知道原始的形状。

原因是大多数 PDF 也不包含表。 PDF中的表格通常是以周围绘制的一些线条绘制的文本,这些线是图形操作,文件中没有将它们连接到它们所包含的文本的任何内容。 转换器必须检测数字的对齐方式,推断网格,并决定哪些运行属于哪个单元,这是一个研究问题,而不是一个解析一个。

一些 PDF 确实通过添加的标签来提供真实的结构,并且转换得更好。 他们是少数:标记的PDF来自Word或InDesign的仔细导出,而不是打印驱动程序。

如果表格是您想要的东西,请手动将其复制到电子表格中,或将 PDF 转换为文本并在那里重塑它。 转换后的 Word 文件不会为您提供单元格。

为什么我的标题合并到段落中?

因为它下面的空间不够大,无法跳过段落规则。

在测试文件的第二页上,标题“注”位于正文上方40个点,而正文线相距18点。 这个间隙是行距的 2.2 倍,这应该是分开的,但事实并非如此,因为只有四次运行的页面上的中值间隙并不是任何东西的可靠估计。 输出是:

Notes Note 14 covers intercompany revenue and the treatment of
deferred items carried over from the prior year.

这是整个问题的诚实形状。 阈值规则在具有足够文本以建立基线节奏的页面上运行良好,而在稀疏的页面上则很差。 标题页、简短的说明、封面或表格通常会作为一个连续的段落回来。

这也是事后最容易解决的问题。 标题对人类读者来说是显而易见的,在正确的地方按下回车需要一秒钟,这比任何工具都能做到正确的时间要少。

扫描页面会发生什么?

什么都没有,这是正确的行为。

我的测试文件的第三页根本没有文本层,只有一个灰色的矩形,用于扫描。 pdf.js 返回零运行,转换器为它生成了零段落。

页面仍然被计算在内。 它在 Word 文件中显示为空页面,因此页面与原始页面保持一致后会中断,这在有人根据页码工作时很重要。 一个静默地掉落它的转换器将每隔一页移动一页。

页面全部为图像的PDF是扫描的,没有转换器可以从中提取文本,因为没有要提取的文本。 需要的是OCR,它读取字母的图片并猜测字符,并带来自己的错误率。 该交易的衡量版本在 破解 OCR 的指南:倾斜超过三个度是破坏扫描的原因,而不是分辨率。

一个有用的经验法则:打开 PDF 并尝试用光标选择一个句子。 如果文本突出显示,转换器可以读取它。 如果您在图像上获得选择矩形,则需要 OCR 首先。

.docx 中出现的内容是什么?

一个压缩文件中的三个文件,这就是真正需要的。

.docx 是一个开放式包装约定档案,标准化为 ECMA-376:包含 XML 部分的 ZIP 以及说明每个部分的清单。 微软自己的 格式概览 走同样的三个部分。 作为 Word 文档打开的最小值为三个条目:

部分 目的
[Content_Types].xml 声明包中每个部分的媒体类型
_rels/.rels 指向主文档部分的点
word/document.xml 内容本身

其他所有文字文件通常携带的所有内容,样式、字体、主题、设置、编号定义,都是可选的。 将它们排除在外,读者会应用其默认值。

测试文档,在三页上 83 个字,到达一个 1,305 字节的 .docx,其 word/document.xml 是 1,169 字节。 我用 Apple 自己的文档阅读器打开它,这是 TextEdit 和 Pages 使用的,它按分页符的完整性呈现了每个段落。 最小的包不是降级的。

该 XML 中的一个细节比看起来更重要。 每次运行都写有 xml:space="preserve"。 没有它,以空格开始或结束的运行会失去它,并且包裹在原件中的每一行都会返回,其最后一个单词与下一个字相连接。

图像会发生什么?

它们被丢弃,Word 文件没有提及。

此处写的软件包有三个部分,它们都不是媒体部分。 一个标志、一个图表、一个扫描的签名、一个嵌入在报告中的截图:全部消失了,没有占位符。 围绕他们的文字就像他们从未在那里一样关闭。

这是相同设计的结果,使输出小而可靠。 跨越图像意味着从PDF中提取它,确定其格式,将其写入 word/media/,为其添加内容类型,添加关系部分,并将绘图元素放置在流中的正确点。 其中每一个都是读者拒绝文件的地方,一个 .docx a word 处理器拒绝打开的地方比一个缺少一个徽标的 .docx 更糟糕。

对于图像是内容而不是装饰的文档来说,这最重要。 报告中的图表转换为无,Word 文件的读者无法知道该图表是否存在。 当散文中提到一个数字时,检查转换旁边的原件。

为什么文件有时会拒绝打开?

控制字符,XML 禁止和 PDF 包含。

PDF 的文本层从打印管道中获取字符,从打印管道中获取字符,从损坏的编码中获取空字节,其他 C0 控制代码,这些代码在文档中没有任何意义。 XML 1.0 不允许其中大部分,甚至逃逸:规范允许的字符范围从选项卡、换行符和回车开始,并跳过 C0 块的其余部分。

失败不是优雅的。 Word 不会警告或删除字符;它拒绝打开文件并表示内容不可读。 因此,转换器在写入之前会剥离这些字符,而不是试图逃避它们。 他们在源头上没有任何意义,他们会花费你整个文件。

如果您曾经收到一个文字处理器拒绝为不可读的 .docx,这是首先要怀疑的,这就是为什么手动编写 XML 的转换器必须考虑它的原因。

你应该转换成单词还是纯文本?

Word 如果您要编辑它,请发送文本,如果您要处理它。

他们共享相同的提取。 区别只是最后写的:一个将段落写入 XML 的 ZIP,另一个将它们写入 .txt 文件。

你想 用 因为
编辑散文并发送 PDF 到 Word 段落结构,分页符,同事可以打开的东西
搜索、grep 或将其提供给脚本 PDF 转文本 没有标记
保持布局准确 两者都没有 编辑 PDF 或获取原始文件
阅读扫描 先行 没有要提取的文本层

第三排是值得坐的一排。 如果布局很重要,转换为 Word 的方向是错误的,因为转换是布局丢失的地方。 询问发送 PDF 的文件以获取其导出的文件。 它需要一条消息,它是保持格式的唯一方法。

转换需要多长时间?

足够长的时间来读取文件,不再。

没有编码步骤,也没有图像处理。 这项工作是解析 PDF 结构,拉取每个页面的文本内容,分组运行,并将 XML 序列化为 ZIP。 测试文件需要几毫秒,因为它是三页,所以没有用。 一个 200 页的报表以 pdf.js 为界限进行解析,它的页数和速度大致呈线性关系。

您在大型文档上注意到的是内存,因为整个文件与解析的结构一起保存在浏览器选项卡中。 这是这里真正的天花板,而不是速度。

输出中应该检查什么?

有四件事,按顺序可能是错误的。

  1. 每一页的第一段。 这是列交错和标题合并出现的地方。
  2. 任何桌子。 确认数字存在,然后接受网格消失并在需要时重建它。
  3. 行尾处的连字符词。 PDF 中一条线断开的单词又回来了,中间有连字符。
  4. 页数。 它应与原稿相匹配,包括任何空白或扫描的页面。

该列表需要十页文档的一分钟,是您可以发送的文件与安静地包含拼接句子的文件之间的区别。

为什么会在浏览器中运行?

因为人们转换的文件是合同、报表、信件、医疗结果和禁运下的东西。

转换是一个解析和一个zip,浏览器的性能非常好。 文件从您的磁盘读取到页面,在那里用为 Web 编译的 pdf.js 解析,组装到内存中的 .docx 中,然后作为下载返回。 没有请求携带文档,服务器上没有任何存储,任何人都没有以后可以删除的内容。

通常的替代方案是一个网站,它可以获取您的 PDF,在您一无所知的机器上转换它,并通过电子邮件向您发送链接。 对于一个很好的公共传单。 对于雇佣合同,这是您没有被要求有意识地做出的决定。

成本是非常大的文件的标签内存,扫描页面没有服务器端的 OCR。 两者都是可见的限制,而不是安静的限制,这是值得拥有的交易。

Comments

0 comments

0/2000 characters

No comments yet. Be the first to share your thoughts!