ARTICLE · 1100618
8 个 OFD 转 PDF 库实测:谁最快、谁的全文字没了、谁在 7M 的文档上崩了
上一篇讲了双向转换为什么不对称。这一篇进数据,看 OFD → PDF 方向的实测结果。
先给结论剧透:
没有一个人在所有维度上赢。 速度第一的还原度崩了,还原度第一的文本最慢,文本最强的最快只排第二。
更麻烦的是:两个 Python 库在 6 个测试文件上各有 2 个直接失败,成功率 67%。
一、参测的 8 个转换器
⚠️ 先读这段:下表是数据快照,不是库的当前状态。所有结论只对表中版本成立 —— OFD 库多为
0.x早期版本,迭代很快,新版大概率修掉本文的若干短板。引用前请先核对版本,见 05 篇「局限 9」。
覆盖 5 种语言,全部实测过。「库版本」是数据可信度的关键列,「库更新」是该版本的发布日期:
go-zc310 | zc310/ofd | ||||
go-ofdgo | xiaoqidun/ofdgo | ||||
rust-easyofd | easyofd-rust | ||||
python-easyofd | easyofd | 2026-04-27 | |||
python-ofd2pdf | ofd2pdf | 2026-07-08 | |||
java-ofdrw | ofdrw | ||||
node-ofd2pdf | @miconvert/ofd-to-pdf | ||||
python-ofdreader | ofdreader |
📌
python-easyofd实际是pip install easyofd ofd2img组合(自动切换库),另一个组件ofd2img版本 0.1.2、更新于 2026-05-07。
测试环境:Ubuntu 26.04.1 LTS (64-bit)字体:fonts-wqy-zenhei、fonts-noto-cjk(已装各种中文字体)样本:来自 zc310/ofd 仓库的 test/testdata参考:数科版式阅读器导出的 *.pdf关于版本时效性,有三点必须说清楚:
- 版本跨度很大
:从 2026-04-27(easyofd)到2026-09-28(三个主力库),相差 5 个月。同一次测试里,有的库是刚发布的,有的已经半年没更新 —— 后者的"失败"更可能是"没人修",而不是"修不了"。 - 失败项尤其容易过期
:本文最刺眼的 python-easyofd4 次失败、python-ofd2pdf4 次失败、python-ofdreader全 FAILED,都发生在未维护或低维护的库上。作者修个 bug 是随时可能的事。 - 许可证是唯一几乎不会变的结论
: jsyzdej/ofd2pdf无许可证,这条不会因为升级而失效。
⚠️
python-ofd2pdf没有许可证,商用项目直接排除。这一条比它的任何性能数据都重要。另外
python-ofdreader模块在本环境未安装,该转换器全部标记 FAILED,实际不参与排名。
测试文件:难度是递进的
hello.ofd | |||
999.ofd | |||
ano.ofd | 发票 | ||
1000-pages.ofd | |||
zsbk.ofd | 签章 | ||
intro.ofd | 复杂图形/多层结构 |
这 6 个难度完全不同的文件,是本篇所有结论的适用范围。
二、速度:Rust 五胜,但别急着欢呼
| rust-easyofd | 45ms | 72ms | 951ms | 166ms | 71ms | 5 | |
| 835ms | |||||||
三个要点:
① Rust 是 5 胜里的"4 胜 + intro 一败"。 5 个样本第一,只有 intro 掉到 1.85s(被 go-zc310 的 835ms 压过)。5 胜无极端值,是这批数据里最干净的一行。
② 差距在多页场景才成倍拉开。1000-pages 一栏:rust 951ms,ofd2pdf 41.29s,43 倍。而 hello 一栏只有 11 倍。单页测试完全测不出真实吞吐。
③ 两个 Python 库合计 4 次失败。
python-easyofd hello FAILED, 1000-pages FAILEDpython-ofd2pdf ano FAILED, intro FAILED最刺眼的是 python-ofd2pdf:hello 136ms,1000-pages 41.29s。 同 一个库,差了 300 倍。栅格渲染路线在多页上会随页数线性累积,且 intro(7.2M,复杂图形)直接崩。
根因记录在项目文档里:
python-easyofd对hello、1000-pages会 crash(list index out of range);python-ofd2pdf基于图片渲染,部分文件失败。教训:
hello通过率 100% 的库,遇到你的真实文档可能直接挂。必须用自己业务的样本重测。
三、体积:谁在膨胀,谁在偷内容
| 614KB | 77.8KB | ||||||
| 36.1KB | 73.1KB | ||||||
| 1.3KB | 1.1MB | 559KB |
python-ofdreader模块未安装,全部标记 FAILED,不参与排名。
核心矛盾:体积和保真度在打架。
intro(7.2M 源)一栏:node 1.1MB,go-zc310 7.6MB,ofdrw 22.6MB,easyofd 38.2MB,ofdgo 34.8MB。 1000-pages(456K 源)一栏:rust 614KB(全场最小),go-zc310 1.8MB,ofdrw 2.3MB,node 7.2MB,ofdgo 38.8MB,ofd2pdf 70.2MB(全场最大)。
python-ofd2pdf 在 1000 页上输出 70.2MB,是全场最差的压缩表现(⚠️ 456K 是源 OFD,70.2MB 是输出 PDF,属跨格式比较;若按源文档口径与数科参考 PDF 相比,比值为 33.13)。go-ofdgo 的 38.8MB 排第二(对应比值 18.30)。项目文档对这两个库的体积定性分别是"基于图片渲染,部分文件失败"和"文件体积较大",未给出根因。
📌 顺带澄清一个常见误传:项目工程记录里"
ofdgo输出 OFD 写 16 位色值"这条,属于 PDF→OFD 方向(03 篇),说的是它生成的.ofd里颜色通道值偏大,与这里 OFD→PDF 的体积膨胀是两回事,别混着引用。
再看和数科参考 PDF 的比值(1.00 = 与数科一致,越接近越说明压缩策略接近,加粗为该列最接近 1.00):
| 1.13 | 0.90 | |||||
| 0.28 | 1.04 | |||||
| 1.36 | 1.07 | 0.96 | ||||
| 0.22 | 0.16 | 1.04 |
go-zc310 是唯一六项里有四项落在 0.84~1.13(贴近 1.00)的:1000-pages 0.84、999 0.92、zsbk 0.90、intro1.13。离群的两项是 hello 2.79 和 ano 0.09。这说明它的压缩行为整体和数科最接近,不是靠"少转东西"取胜的。
rust-easyofd的zsbk = 0.05(1.4M → 77.8K)看着惊人,但第 4 节会告诉你它的zsbk像素只有 94.02% —— 体积小是因为丢内容。
四、还原度:像素相似度,暴露了谁在偷懒
以数科版式阅读器导出的 PDF 为基准,96 DPI 渲染,算 1 - 平均归一化色差:
| 99.95% | 99.32% | ||||||
| 99.62% | 99.50% | ||||||
| 99.62% | 98.49% | ||||||
| 44.99% | 73.66% | ||||||
| 37.74% |
4.1 三个硬故障
rust-easyofd intro 44.99% 1000-pages 73.66%python-easyofd intro 37.74%intro 这份 7.2M 的文档,是照妖镜。 任何在 hello 上接近 99% 的库,到 intro 都现原形:
node-ofd2pdf 96.29% ← 掉得最少go-ofdgo 99.62% ← 几乎无损go-zc310 99.42%java-ofdrw 98.94%rust-easyofd 44.99% ← 崩了python-easyofd 37.74% ← 崩得更狠项目文档写得很直接:
rust-easyofd 在 intro、1000-pages 相似度明显偏低(46%、74%),说明对含复杂图形/签章文件的还原能力弱。
注意 1000-pages 一栏更能说明问题 —— rust 在这一栏的像素只有 73.66%,但它的输出 PDF 只有 614KB(该栏最小)、速度 951ms(该栏最快)。"最快 + 最小 + 还原最差"三件事同时发生在同一个库身上,这不是巧合:它没转该转的东西。
4.2 一个方法论警告
文档里有一条必须记下的注意事项:
intro 的像素对比跳过 14~19 页(数科导出的参考 PDF 这几页背景图丢失,不计入对比)。
也就是说,参考基准本身在这 6 页上是有缺陷的。如果不排除,intro 一栏的所有数字都会被系统性拉低。
复现:
python3 tools/compare_pdf.py 96 <file>
五、文本能力:这是最容易被忽略、也最影响业务的维度
转换完了。用户接下来会做什么?
在 PDF 里 Ctrl+F 搜索 → 需要文本层复制一段文字贴进系统 → 需要文本层归档系统做全文检索 → 需要文本层把 PDF 内容喂给 NLP/RAG → 需要文本层"转换成功"和"转换出的 PDF 能用",差距就在这里。
5.1 提取字符数
单位:字符数(chars)
| 4249 | 1938 | |||||
| 7280 | ||||||
| 28 | ||||||
| 10194 | ||||||
| 0 | 0 | |||||
| 0 | 0 | 0 |
两个 0 值来源完全不同,性质天差地别:
go-ofdgo 0 ← 转换成功,但文本层基本是空的(不是提取不出来,是没写进去)python-ofd2pdf 0 ← 走的是"整页渲染成图片"路线,本来就没有文本层go-ofdgo 的 0 尤其要注意 —— 它的像素相似度 99.62%(intro)、98.49%(999)是全场前列,画面完美,但一个字都搜不到。项目文档:
go-ofdgo 文本提取能力弱(hello=8/25、999=61/3934 字符)。
参考值是 hello=25、999=3934。它提取出 8 和 61,分别只有 32% 和 1.6%。
这就是本文最想传达的一句话:像素相似度 99% 和"能用",是两件事。
5.2 文本相似度(4-gram Jaccard)
字符数只能说明"有多少",相似度才说明"对不对"。
| go-zc310 | 99.07% | 73.85% | 95.85% | 98.85% | 4 | ||
| 78.68% | |||||||
| 45.16% | |||||||
| 0.00% | 0.00% | ||||||
go-zc310 4 胜,而且是唯一在长文档上稳定的:
zsbk 98.85% (参考 1150 字符)999 95.85% (参考 3934)ano 99.07% (参考 7139)intro 73.85%go-ofdgo 的 ano 和 intro 是 0.00% —— 和"转换成功"并列出现,冲击力很强。
为什么有些库字符很多但相似度很低? 项目文档点名了 go-zc310 的相反问题:
go-zc310 保留文本对象,文本顺序正确(如「欢迎使用」顺序无误),但字形间插入空格(如
H e l l o)使 4-gram 相似度偏低,内容本身完整。
以及:
文本相似度对提取顺序/换行敏感,得分偏低不代表内容缺失。
所以正确的读法是:
字符数 0 → 确定不能用(无文本层)字符数少 + 顺序对 → 可能是好的(可以优化字距)字符数多 + 相似度低 → 顺序/切分有问题(要修切分逻辑)复现:
python3 tools/compare_text.py <file>
六、质量总结与官方结论
| 100% | 最佳 | 最佳 | ||||||
| 100% | ||||||||
| 100% | 最佳 | |||||||
| 无 | ||||||||
| 100% | ||||||||
| 100% |
项目文档给的结论(原文摘录):
- rust-easyofd
:速度最快(5 胜),压缩率最好(2 胜),推荐首选 - go-zc310
:intro.ofd 最快(835ms),文本相似度最高(4 胜)、像素还原 2 胜(ano、zsbk),文本提取最完整(ano=7280 字符),适合需要搜索/复制文本或处理复杂文档的场景 - go-ofdgo
:像素相似度 2 胜(intro、999),但文件体积较大、文本提取较差 - python-easyofd
:部分文件转换失败,intro 还原度差 - python-ofd2pdf
:基于图片渲染,无法提取文本 - java-ofdrw
:兼容性好,但速度较慢;1000-pages 文本相似度最高(78.68%),小文件还原度接近数科 - node-ofd2pdf
:兼容性好,文本提取字符数上 999(4249)、zsbk(1938)领先 - rust-easyofd
:对含复杂图形/签章文件(intro、1000-pages)还原度差(46%、74%)
⚠️ 文档自己列出的局限性(请一并读完)
本测试仅运行 1 次,无方差/置信区间,无法判断差异是否显著 - 未记录机器规格
(CPU 型号/频率/核数/内存/是否 SSD),绝对耗时不可移植 Java/Node 未预热(JIT 未达稳态),首次运行吃亏,"Java 最慢"的结论需谨慎 无冷启动/热启动分离,单次测量包含类加载、字体扫描等开销 仅相对排名有意义,绝对毫秒数在不同机器上会完全不同 Rust 5 胜为全面领先,无明显极端值 以上结论由 AI 根据测试数据自动汇总生成
建议:手工核对输出 PDF 效果,选择合适的库。不同 OFD 文件结构差异较大,实际效果可能与基准测试结果不同。
测试输出 PDF 文件可在 Releases 页面下载。
七、按场景的实用建议
| go-zc310 | ||
| go-zc310 | ||
| go-ofdgo | intro | |
| rust-easyofd | ||
| rust-easyofd | ||
| node-ofd2pdf | ||
| 只是要个图片 | ||
| 商用项目 |
八、一句话收束
OFD→PDF 的正确问法不是「哪个最快」,而是: · 我的文档有复杂图形吗? → 有,先验 intro 类样本 · 转换后要能搜索/复制吗? → 要,看文本相似度不看像素 · 签章能画出来就够吗? → 够(信任链另算) · 能进商用吗? → 先查许可证先按这四问筛掉一半选项,再看速度排名 —— 顺序反了就会被榜单骗。
参考资料
ofd-benchmark/docs/ofd-to-pdf.md(本文全部数据来源) ofd-benchmark/README.md(项目索引与复现入口) 库能力全景见 ofd-benchmark/docs/ofd-libraries.md(66 个库)