UUsefulCrate 你的文件永远不会离开浏览器

首页 › 指南 › 文档

PDF 转 Word:什么保得住,什么保不住

转换失败几乎从不大声出现。基于 134 份真实文档的全量实测,真正决定你的 PDF 转得干不干净的,是文字层、字符映射表、图片解码器,还有那些被撕成两半的单词。

2026-10-16 · 10 分钟阅读

一句话结论:PDF 转 Word 的转换器读的不是你看到的那份文档,而是 存在图片旁边的"文字层"——而这一层缺斤短两是常态:没内嵌的字体没有字符映射表、引擎解不开的图片格式、 把 flight 撕成两半的连字字形。我们用 134 份真实 PDF 全量压测了自己的浏览器端转换器,把每一次 失败都追到了文件内部的原因。这就是决定你转换结果干净与否的真正因素。

测试样本不是一批规整的小样例,而是 134 份真实文档——发票、商业计划书、试卷、政府表格、中英混排—— 用一台基于 pdf.js 的转换器端到端跑完。核心结果:130 份文件在打补丁前后转换结果完全一致,4 份文件丢了 全部中文,1 份产出永久乱码。所有失败都是静默的:没有报错、没有崩溃,文件只是"错着出来了"。

这种静默正是本文的主题。转换器几乎从不大声失败——它失败的方式,是递给你一份看起来完成了、 实际上没有的文档。

先说清楚:转换器读的是文字层,不是画面

PDF 不像 Word 那样是"文档格式",它是一套打印指令:把这个字形放到这些坐标上, 在这个矩形里画那张图。字形本身完全不必携带自己的身份信息。所谓"转成 Word",是转换器把这套指令 读回来,仅凭坐标试图重建段落、标题和列表。

这就是为什么扫描件是硬边界。扫描版 PDF 里是页面的照片——一个字形指令都没有,只有像素。 没有文字层,就没有东西可转。如果转换器对扫描件返回一个空 Word 文件还一声不吭,它就在隐瞒你的 文档最重要的事实。靠谱的做法是明说:这几页没有可读文字,你需要的是 OCR,那是另一个产品。

就算是没扫描过的 PDF 也埋着图片形状的陷阱。扫描后套 OCR 的混合文件、传真归档、老系统导出的 文件常用 JBIG2——一种双色位图格式。转换引擎若没有 JBIG2 解码器,整页整页的内容会从输出里消失, 照样没有报错,因为引擎根本没收到那张图。

中文整段消失:没内嵌的字体和字符映射表

我们实测里代价最高的缺陷不是乱码,而是什么都没有。

很多中文 PDF 不内嵌字体,字体描述里只写一句:"用 UniGB-UCS2-H 这张预定义映射表 解码我的字符编码"——这张表存在文件外面,存在于阅读器里。转换引擎有这张表,每个字符都能 归位;没有这张表,字体加载失败——而失败的样子不是报错,是抽取器把原始字符码原样交回来, 或者干脆什么都不给。

我们用一份 32 页的中文文档量化了这件事。修复前,转换器抽出 459 个词——基本只剩 页码和目录省略号。补上映射表之后(pdf.js 按需从 cMapUrl 目录加载),同一份文件产出 16,996 个词。同样的文件,37 倍的文字,中间没有任何一次报错。

在 134 份全量样本里,有 4 份文件这样丢了中文,约占 3%——光这 4 份就救回了 24,533 个字符。

这条缺陷有两点特别难缠:

谁都修不了的乱码——Acrobat 也一样

另一类更罕见的失败长得像,本质完全不同。有些 PDF 里的 CID 字体根本没带字符映射: 文件从头到尾没说过哪个字形编号对应哪个字符。信息不存在,任何转换器都还原不出来——因为没有 东西可还原。

我们的 134 份里恰好 1 份中招,特征非常好认:同一页里,有的行转换得完美无缺,有的行出来是 +$1*=+28。同一页两种字体——一种内嵌了映射,一种没有。

如果你碰上了:这不是转换器的错,换哪家都一样。PDF Association 明确说过,PDF/A 合规级别 "b" 只保证视觉还原,不要求内嵌字体带 Unicode 映射。常见来源是老工具链——早期 Office 导出、没装 CMap 包的 LaTeX、6.0 之前的 LibreOffice。包括 Adobe Acrobat 在内,所有人唯一的 绕法是对出问题的那一页跑 OCR。知道这一点,能帮你省下一个下午的"怪工具"时间。

还有一个数字值得知道:风险特征(CID 字体没带映射)出现在 5 份文件里,真正产出乱码的 只有 1 份。危险结构多数时候能靠兜底路径正常转换。下结论看抽出来的文字,别看吓人的内部结构。

图片消失的三种方式,一个字都不提

一份 701 页、41 MB 的中英混排文档教会了我们图片这一课。它含 775 张真图,我们的转换器第一版 只提出 253 张。

  1. 解不开的格式。丢失图片里 500 多张是 JPEG 2000——pdf.js 不自带它的解码器。 每张解不开的图返回空值,代码跳过它,计数器纹丝不动。解法是内置一个 WebAssembly 的 JPEG 2000 模块——但更深一层的教训是:解码器缺失如果不打点统计,就是静默的。每张解不开的图都要 计数,并把数字打出来。
  2. 预算变成了闸门。第一版按文档顺序花字节预算:前 400 页把它花光,于是 501–643 页在一份 62 MB 的输出文件里一张图都没有——而其他所有指标看起来都正常。 预算应该按比例分配,不该是先到先得的闸门。
  3. 永远不来的对象。真实 PDF 里有些图片对象是永久损坏的——引用在,数据不在。 我们旧代码对每张取不到的图干等 8 秒。一份 31 张坏图的文件耗时 252 秒,几乎精确等于 31 × 8。 改成按文档阶梯等待(首张给足,其后收短)之后,同一份文件 23 秒跑完——而不可读计数 一张不差。对任何"提速"都要多心:我们没有救回一张图,只是不再等那些永远不会来的图。

一页坏,不该拖垮三十九页好的

一份 20 页的文档里只有第 2 页损坏——压缩流坏了。另外 19 页好得很。第一版实现却报"转换失败", 因为那一页抛出的错误逃逸出去,中止了整份文档。

正解是逐页容错:计数、跳过、继续,最后告诉用户——"20 页中有 2 页内容损坏、无法读取。" "整份失败"应该只留给每一页都失败的情况——那通常意味着这份文件根本没有文字层。

被撕成两半的单词,和搜索失效

更隐蔽的失败发生在单个词上。两种机制,全都看不见:

这两类都能修一部分。在英语里不能收尾一个词的连字(fi、fl、ffi) 可以安全接回;ff 和 st 能收尾(off、first),它们的撕口真正 有歧义,最好别碰。完美不在菜单上——诚实的工具会告诉你哪些它修不了。

什么保得住,什么保不住

通常保得住通常保不住
文字内容与阅读顺序精确定位(Word 会重排一切)
段落、标题、列表多栏版式(各栏合并成一条流)
加粗 / 斜体 / 颜色 / 对齐 / 缩进表单域(勾选框变成文字或消失)
内嵌图片(可解码的格式)文本框和浮动图形
分页图表(顶多作为死图到达)

这不是小工具独有的实现短板——忠实还原分栏和表单域是桌面排版引擎的活儿,这正是大多数在线 转换器要把你的文件传到服务器的原因。浏览器本地转换器用这些功能换来了"文档永不离开你的电脑" 的保证。转换之前,先想清楚你要哪一个。

转换前 30 秒检查清单

  1. 文字选得中吗?打开 PDF,试着选中一句话。选不中,它就是扫描件——你需要 OCR,不是转换器。
  2. 是中文或其他 CJK 文档吗?未内嵌的 CJK 字体是经典静默失败场景。如果转换结果 整段整段地丢中文,问题就出在字符映射表——换一个内置了映射表的转换器再试。
  3. 看两头,别只看中间。翻第一页、最后一页、中间随便一页。"预算闸门"类的 bug 藏在长文档的后半段。
  4. Ctrl+F 搜一个你看得见的词。页面上明明有 flight,Word 里却搜不到, 你的词被撕开了——连字或字距问题。
  5. 大致核对图片数量。一份十页的宣传册不应该产出一个只有三张图却 60 MB 的 Word 文件。

134 份文件给我们最大的教训是:转换失败几乎从不发出声音。会告诉你"3 页无法读取、5 张图 解不开、CJK 字符映射已加载"的转换器,比那个宣称 100% 成功、然后递给你一场安静灾难的转换器, 值钱得多。要数字。

← 全部指南