OCRmyPDF 下游打包与维护指南:v17 依赖架构、版本策略与发行版集成
导读
本文是写给 下游发行版打包维护者与平台移植者 的实操指南,围绕官方维护文档 docs/maintainers.md 展开。内容覆盖 OCRmyPDF v17 之后的可选依赖架构(Ghostscript 不再是唯一选择)、按功能拆分的运行时依赖清单、官方给出的依赖速查矩阵与最小/推荐安装组合、可用于 debian/control 的依赖声明样例,以及版本号管理、JBIG2 打包注意点、shell 补全安装等发行版集成细节。读完本文,你将能判断自己的目标发行版缺什么依赖、各依赖缺了会损失哪些能力,并知道如何为 OCRmyPDF 编写正确的依赖元数据与打包配置。
1. 这篇文档服务谁:packagers 与 porters
docs/maintainers.md 开篇即说明它面向两类人:
- 为下游发行版打包 OCRmyPDF 的维护者(Debian、Fedora、Arch、Homebrew、FreeBSD 等);
- 希望把 OCRmyPDF 移植到新平台的开发者。
文档的核心诉求是:帮打包者把「运行依赖」和「可选能力」区分清楚,避免为了一个可选项引入整套重型依赖,也避免因为缺少某个组件导致核心 OCR 功能静默降级而不自知。
在动手打包一个新平台之前,文档给出的一个关键经验是:先确认你的发行版能否打包 pikepdf(docs/maintainers.md)。pikepdf 与 OCRmyPDF 同作者,是一个 Python 与 C++14 混合的包,构建要求远比纯 Python 包苛刻。若 pikepdf 无法在目标平台上构建,OCRmyPDF 的移植也就无从谈起——pikepdf>=10 被列为 pyproject.toml 中的硬性运行时依赖。
2. v17 的架构级变化:Ghostscript 从「必需」到「可选」
::: versionchanged 17.0.0
维护文档用 versionchanged 17.0.0 标注了一个重要变更:Ghostscript 不再是严格必需的运行时组件(docs/maintainers.md)。OCRmyPDF v17 为两大核心功能分别提供了可替换的代码路径:
| 功能 | 替代方案 | 说明 |
|---|---|---|
| PDF 栅格化(转图片供 OCR) | pypdfium2(Python 包) | 可选路径 A |
| PDF 栅格化 | ghostscript(系统二进制) | 可选路径 B |
| PDF/A 转换 | verapdf(校验)+ pikepdf(推测式转换) | 可选路径 A |
| PDF/A 转换 | ghostscript(系统二进制) | 可选路径 B |
文档同时强调:Ghostscript 仍是功能丰富、历史悠久的成熟工具,但近期版本引入了一些兼容性挑战,v17 正是通过替代代码路径来规避这些问题的。因此给用户的最佳体验建议是 GS 与替代工具都装上,运行时再按可用性选择(docs/maintainers.md)。
这一设计在源码层面有清晰印证:
src/ocrmypdf/_exec/_probe.py提供了统一的ToolProbe探测机制,通过version()/available()判断某个外部可执行文件是否存在且版本可用,每个外部工具(Ghostscript、Tesseract、unpaper 等)各自在src/ocrmypdf/_exec/下用ToolProbe描述自己的探测方式;- Ghostscript 路径在 src/ocrmypdf/_exec/ghostscript.py 中定义
PROBE = ToolProbe(program=GS),其中 Windows 上使用gswin64c、其他平台使用gs; - 而 pypdfium2 路径是独立的 built-in 插件 src/ocrmypdf/builtin_plugins/pypdfium.py,只有当
pypdfium2可用或用户显式指定--rasterizer pypdfium时才生效。
2.1 PDF 栅格化:pypdfium2 优先
维护文档将 pypdfium2 列为「优先项」。在 docs/installation.md 中有更直白的解释:pypdfium2 基于 Chromium 使用的 pdfium 库提供快速栅格化,性能通常优于 Ghostscript,因此可用时优先。从源码看,pypdfium2 是纯 Python 依赖(pyproject.toml 中 pypdfium2>=5.0.0),不需要系统包管理器参与,这也是它成为发行版友好选项的重要原因。插件实现里还专门加了线程锁——pdfium 库并非线程安全(src/ocrmypdf/builtin_plugins/pypdfium.py),打包者无需处理这一点,但它提醒我们该路径是进程内调用而非子进程。
2.2 PDF/A 转换:verapdf + pikepdf 的「推测式转换」
PDF/A 是 OCRmyPDF 的默认输出格式要求。v17 之前这条路只能靠 Ghostscript;v17 之后,OCRmyPDF 先用 pikepdf 直接添加元数据与 ICC 色彩配置做一次推测式(speculative)转换,再用 verapdf 校验产物是否符合 PDF/A 规范。只有校验通过才跳过 Ghostscript;校验不通过则回退到 Ghostscript 路径(docs/installation.md)。
这意味着 verapdf 缺失时 PDF/A 能力并不完全丧失(只要还有 Ghostscript),但 verapdf 缺失会堵死那条更快的路径。因此安装指南建议两个都装,以获得最佳兼容体验(docs/installation.md)。
3. 按功能拆分的完整运行时依赖清单
维护文档把 OCRmyPDF 的运行时依赖按功能角色划分,而不是简单罗列包名,这对打包者极其有用——它能直接回答「砍掉某个包会损失什么」:
3.1 PDF 栅格化(把 PDF 页转成图片供 OCR)
pypdfium2(Python 包)——或——ghostscript(系统二进制)- 推荐:两者都装,兼容性最好。
3.2 PDF/A 转换
verapdf(系统二进制,配合 pikepdf 的推测式转换)——或——ghostscript(系统二进制)- 推荐:两者都装。
3.3 OCR 引擎
tesseract-ocr(系统二进制)——MVP 必需。
注意:Tesseract 依赖 SIMD 指令集获得性能,官方只在 ARM 与 x86_64 上提供完善支持,其他处理器架构上性能可能较差(docs/maintainers.md)。这一点对面向小众 CPU 架构的发行版尤其需要评估。
3.4 文本渲染(把 OCR 结果写进 PDF 文本层)
fpdf2(Python 包)——必需;uharfbuzz(Python 包)——必需;- Noto 字体(系统包)——推荐。不同发行版包名不同:Debian/Ubuntu 为
fonts-noto,Fedora 为google-noto-fonts-all;Homebrew 没有统一的 Noto 包,只有按字体族拆分的 cask(如font-noto-sans)。
fpdf2 与 uharfbuzz 承担的是文本层渲染引擎:fpdf2 负责生成 PDF 文本层,uharfbuzz 负责文本塑形(shaping),保证多语言(尤其非拉丁文字)正确排布。它们替代了旧版基于 hOCR 的渲染器(docs/installation.md)。OCRmyPDF 只内置一款拉丁字体,其余字形依赖系统安装的字体发现——这正是 Noto 字体被「推荐」而非「必需」但仍建议打包的原因。若缺字体导致某些字符无法渲染,OCRmyPDF 会提示具体字符码位(例如 'Ꮳ' U+13E3 CHEROKEE LETTER TSA),安装对应 Noto 字体族即可(docs/installation.md)。
3.5 其他可选依赖
unpaper(系统二进制)——可选,启用--clean与--clean-final;pngquant(系统二进制)——可选,启用--optimize 2与--optimize 3;jbig2enc(系统二进制)——可选,改善单色图像的压缩比。
这三者是「能力开关」而非基础依赖:缺了 unpaper,仅 --clean 相关选项报错;缺了 pngquant,仅较高档位的优化不可用;缺了 jbig2enc,输出文件会更大但流程照常。
3.6 Windows 打包者的额外注意点
在 Windows 上,OCRmyPDF 除 PATH 之外还会查注册表定位 Tesseract 与 Ghostscript(docs/maintainers.md)。对应的实现位于 src/ocrmypdf/subprocess/_windows.py:Ghostscript 读取 HKEY_LOCAL_MACHINE\SOFTWARE\Artifex\GPL Ghostscript 下的最新版本子键,Tesseract 读取 HKEY_LOCAL_MACHINE\SOFTWARE\Tesseract-OCR 的 InstallDir 值。因此 Windows 安装包只要写对了注册表项,OCRmyPDF 即可自动发现,无需强制用户改 PATH。
4. 官方依赖速查矩阵(v17.0.0 引入)
维护文档在 versionadded 17.0.0 标记下提供了一张面向打包者的依赖决策矩阵(docs/maintainers.md),把「功能 → 选项 1 → 选项 2 → 备注」浓缩成一张表:
| Feature | Option 1 | Option 2 | Notes |
|---|---|---|---|
| PDF rasterization | pypdfium2 (Python) | ghostscript (binary) | pypdfium2 preferred when available |
| PDF/A conversion | verapdf + pikepdf | ghostscript | verapdf validates speculative conversion |
| Text rendering | fpdf2 (Python) | - | Required, replaces legacy hOCR renderer |
| OCR | tesseract-ocr | --ocr-engine none |
Can be skipped entirely |
其中两条信息容易被忽略,值得展开:
- 文本渲染这一行没有「选项 2」——fpdf2 是唯一的文本层渲染实现,属于硬依赖。这与 pyproject.toml 中
fpdf2>=2.8.0、uharfbuzz>=0.53.2被列入强制dependencies一致。 - OCR 可以完全跳过——通过
--ocr-engine none可以让 OCRmyPDF 只做图像清理、优化等处理而不调用 Tesseract(src/ocrmypdf/builtin_plugins/null_ocr.py 即该空引擎的实现)。因此对某些只想用其 PDF 处理管线、不想背 Tesseract 依赖的场景,存在合法的最小裁剪路径。
4.1 最小可行安装(MVP)与推荐安装
根据矩阵,文档给出两档打包基准(docs/maintainers.md):
最小可行安装:
tesseract-ocr+(pypdfium2或ghostscript)+fpdf2
推荐安装(完整能力):
tesseract-ocr+pypdfium2+ghostscript+verapdf+fpdf2+unpaper+pngquant+jbig2enc
注意安装指南中的推荐清单比维护文档多了 uharfbuzz 与 Noto 字体,因为前者站在最终用户角度、后者站在打包最小依赖角度(docs/installation.md)。两处都强调:64 位版本受官方支持,32 位不受支持(Linux 上可能碰巧可用,Windows 上明确不支持)。
4.2 关键警告:PDF/A 能力可能整体消失
维护文档附了一条 warning(docs/maintainers.md):
如果既没有安装 Ghostscript,verapdf 也不可用,则 PDF/A 输出无法产生,输出将退化为普通标准 PDF。
这是一处相对旧版配置的破坏性变更——少数此前只靠 Ghostscript 之外机制输出 PDF/A 的罕见配置将受影响。打包时务必想清楚:你的依赖组合到底是「三选一都有」,还是「两头都空」。兜底判断完全由运行时探测驱动:Ghostscript 的探测在 src/ocrmypdf/_exec/ghostscript.py 中通过 ToolProbe 完成,探测不到就当作不可用,管线随即走对应降级分支。
5. 移植新平台的第一道关卡:pikepdf 之外还要过一遍版本门
维护文档反复强调 pikepdf 的可打包性是前提(见第 1 节)。除此之外,打包者还应当对照 pyproject.toml 逐条核对:
requires-python = ">=3.11"
dependencies = [
"fpdf2>=2.8.0",
"img2pdf>=0.5",
"packaging>=20",
"pdfminer.six>=20260107",
"pi-heif",
"pikepdf>=10",
"Pillow>=10.0.1",
"pluggy>=1",
"pydantic>=2.12.5",
"pypdfium2>=5.0.0",
"rich>=13",
"typing-extensions>=4.12; python_version < '3.13'",
"uharfbuzz>=0.53.2",
]
其中有几条值得打包者专门注意:
- Python 版本门槛为 3.11+,安装指南建议 3.12+(docs/installation.md);
- 系统二进制类依赖(Tesseract ≥ 4.1.1、可选 pypdfium2 之外的 Ghostscript 9.54+ 等)无法由 pip 提供,必须由系统包管理器满足(docs/installation.md)。这是打包者与「pip 用户」责任边界所在:pip 安装并不能补全外部程序;
pi-heif被刻意设计成可安全移除的依赖——源码注释直接写明 "maintainers: if this is removed, it will NOT break"(pyproject.toml),这与本文第 9 节的 HEIF/HEIC 降级机制呼应;pdfminer.six、pikepdf、Pillow、pydantic、rich等还有各自的>=下界,通常对应修复了特定缺陷的版本,不建议发行版为追新而盲目放宽,也不建议低于下界打包。
6. 版本管理:hatch-vcs、__version__ 与发行版修订号
版本号策略是发行版维护者与上游最容易起摩擦的点。维护文档指出(docs/maintainers.md):
- OCRmyPDF 的版本由 hatch-vcs 从 Git 派生,Git 是「单一事实来源」。这种策略对某些发行版不友好——例如发行版往往需要在版本号上标注「本地打了补丁」之类的差异。
- 若确需覆盖版本,文档给了两条出路:
- 直接修补
src/ocrmypdf/_version.py中的__version__变量; - 设置环境变量
SETUPTOOLS_SCM_PRETEND_VERSION为所需版本。
- 直接修补
在本文对应的仓库快照里,可观察到的实际状态是:构建后端为 hatchling(pyproject.toml),pyproject.toml 中静态声明了 version = "17.8.1",而 src/ocrmypdf/_version.py 中同样持有 __version__ = "17.8.1"(ruff 配置也将其标注为自动生成文件,见 pyproject.toml)。docs/conf.py 则通过 importlib.metadata 读取已安装包的版本用于文档构建(docs/conf.py)。这意味着无论版本来自 Git 派生还是静态注入,最终对外可见的版本入口高度集中,发行版只需要保证该单一入口被正确改写,即可让 ocrmypdf --version、文档版本号等处保持一致。版本发布流程可参考仓库内的 src/ocrmypdf/RELEASE.md。
7. jbig2enc:专利已过期,v17 起仅支持无损编码
jbig2enc 是一个 JBIG2 编码器,OCRmyPDF 只要能在 PATH 上找到它就会自动用于单色图像压缩(docs/maintainers.md)。历史上部分发行版因 JBIG2 内含专利算法而拒绝打包,但文档明确指出:
所有 JBIG2 专利已于 2017 年全部过期。
因此官方建议:条件允许时尽量把 jbig2enc 一并打包,以改善 OCRmyPDF 的压缩率。Debian/Ubuntu、Fedora 与 AUR 的官方包目前都省略了 JBIG2 编码器,OCRmyPDF 缺它仍可正常工作,只是输出文件更大;用户也可以从源码构建 jbig2enc,把它放到 PATH 上即可被自动识别(docs/installation.md)。构建步骤的细节见 docs/jbig2.md。
jbig2enc 打包时还需注意一条 v17.0.0 的功能删减(note 标注,docs/maintainers.md):
有损 JBIG2 编码已在 v17.0.0 移除。此前该功能以「caveat emptor」(买者自负)方式提供,但由于存在有据可查的字符替换错误风险,官方决定移除该选项。现在只支持无损 JBIG2 压缩。
对应命令行选项 --jbig2-lossy 随之消失(docs/installation.md 再次以 warning 形式重申)。如果下游发行版仍停留在引用 --jbig2-lossy 的旧版本或旧文档,需要同步更新。
8. 可直接参考的 debian/control 依赖声明样例
维护文档直接给出了一段完整的 debian/control 依赖规格样例(docs/maintainers.md),这是全文最「拿来即用」的部分,完整摘录如下:
Depends:
fonts-noto,
fpdf2 (>= 2.8),
ghostscript (>= 9.55), # Not strictly required, but best user experience
icc-profiles-free,
img2pdf,
python3-coloredlogs,
python3-deprecation,
python3-pdfminer (>= 20181108+dfsg-3),
python3-pikepdf (>= 8.14.0),
python3-pil,
python3-pluggy,
python3-reportlab,
python3-rich,
python3-uharfbuzz, # Not currently in Debian
tesseract-ocr (>= 5.0.0),
zlib1g,
${misc:Depends},
${python3:Depends},
Recommends:
cyclopts, # Not currently in Debian
jbig2
paddleocr, # Not currently in Debian
pngquant,
pypdfium2, # Not currently in Debian
unpaper,
verapdf, # Not currently in Debian
Suggests:
ocrmypdf-doc,
python-watchdog,
读这张表可以学到几层打包思路:
Depends(硬依赖)被压缩到最小——凡是缺了会导致核心管线无法工作的项才放进来,例如fpdf2(文本层渲染硬需求)、pikepdf、tesseract-ocr;Recommends(推荐依赖)承载可选能力开关——jbig2、pngquant、unpaper、verapdf、pypdfium2全部归入此档,对应「装了更好、不装可用」的定位,与第 3、4 节的矩阵完全对应;- 注释坦诚标出「Not currently in Debian」——如
python3-uharfbuzz、cyclopts、paddleocr、pypdfium2、verapdf,说明这是一份「上游理想清单」,下游具体发行版需要结合自身仓库现状取舍; - 版本号下界与安装指南呼应——
fpdf2 >= 2.8、ghostscript >= 9.55、tesseract-ocr >= 5.0.0等与 docs/installation.md 列出的最低版本要求一致(Tesseract 官方要求 4.1.1+,样例进一步约束到 5.x,属发行版自身的收紧策略)。
值得强调:ghostscript (>= 9.55) 行内注释写着「Not strictly required, but best user experience」——这是 v17 依赖策略的缩影:Ghostscript 从 Depends 的语义中心退为「增强体验」,但发行版若完全省略它,就必须确保 pypdfium2/verapdf 组合能覆盖栅格化与 PDF/A 两条路径(见 4.2 的降级警告)。
9. 其他发行版集成事项
9.1 Shell 补全必须随包安装
维护文档提醒:请务必安装命令行补全脚本,具体位置见安装文档(docs/maintainers.md)。对应文件就在仓库的 misc/completion/ocrmypdf.bash 与 misc/completion/ocrmypdf.fish。安装指南给出的安装位置(docs/installation.md):
- bash:将
ocrmypdf.bash复制为/etc/bash_completion.d/ocrmypdf; - fish:将
ocrmypdf.fish复制到~/.config/fish/completions/ocrmypdf.fish。
bash 版补全大概率兼容 zsh,但官方尚未确认——zsh 发行版打包时需自行验证。
9.2 32 位 Linux 支持:不承诺、不设障
只要全部依赖仍有 32 位版本可用,OCRmyPDF 在 32 位 x86/ARM 上「应该能继续工作」,但官方明确不在 32 位平台上测试(docs/maintainers.md)。安装指南的措辞更强硬:不支持任何 32 位系统,包括 32 位 Python 与 Windows 上的 32 位 Ghostscript(docs/installation.md)。加上 Tesseract 的 SIMD 依赖(见 3.3),32 位或小众架构的打包者需要对性能和稳定性有合理的预期管理。
9.3 HEIF/HEIC:可移除、可优雅降级
OCRmyPDF 默认安装 pi-heif(PyPI 包),用于在命令行把 HEIF/HEIC 图片转成 PDF(docs/maintainers.md)。如果发行版没有该库,可以安全地将其排除——OCRmyPDF 会自动优雅降级,只是失去 HEIF/HEIC 输入支持。源码侧的证据是 pyproject.toml 中 pi-heif 依赖旁的那句维护者注释:移除它不会破坏构建,这是上游刻意留给发行版的裁剪空间。
10. 打包自查清单
把维护文档的内容收敛成一份可执行的自查清单,供打包与发布前逐项核对:
- 前提关卡:能否打包 pikepdf?(Python + C++14,构建要求苛刻)
- 栅格化路径:是否提供了 pypdfium2(Python)与/或 ghostscript(系统二进制)?推荐两者皆备。
- PDF/A 路径:是否提供了 verapdf + pikepdf 与/或 ghostscript?⚠️ 若 GS 与 verapdf 都不在,PDF/A 输出将退化为普通 PDF。
- OCR 路径:是否提供 tesseract-ocr?若明确不需要 OCR,是否已通过
--ocr-engine none验证空引擎流程可用? - 文本层渲染:是否提供 fpdf2(必需)与 uharfbuzz(必需)?是否随包带上/推荐 Noto 字体以获得完整字形覆盖?
- 能力开关:unpaper(
--clean/--clean-final)、pngquant(--optimize 2/3)、jbig2enc(单色压缩)是否至少进入Recommends? - 版本一致性:是否只改
src/ocrmypdf/_version.py的__version__(或使用SETUPTOOLS_SCM_PRETEND_VERSION),保证--version与文档版本一致?是否已声明本地补丁修订号? - JBIG2 合规:若打包 jbig2enc,确认仅支持无损模式,
--jbig2-lossy在 v17 已移除。 - 补全脚本:bash/fish 补全是否随包装到了系统路径?
- 架构声明:是否明确 32 位不受官方测试支持,Windows 注册表探测路径(Artifex/Tesseract-OCR)是否被安装器正确写入?
结语:把「依赖」翻译成「能力」,是维护文档的核心方法论
docs/maintainers.md 表面上是一份依赖清单,实则提供了一套以功能角色为纲的依赖决策方法:每引入或剔除一个组件前,先问它服务的是「栅格化」「PDF/A」「OCR」「文本层渲染」中的哪条链路,再对照官方矩阵判断是否会触达降级分支(尤其是 PDF/A 全线缺失的警告)。这种「依赖 = 能力」的视角,配合 pypdfium2/verapdf 等 v17 新路径的源码佐证,能让发行版在依赖裁剪、能力保留与用户预期管理之间做出可解释的取舍。对想要移植或打包 OCRmyPDF 的维护者而言,本文覆盖的自查项就是一份与上游对齐的验收基线。
提示:以上实现细节均可在仓库中对照验证——维护指南见 docs/maintainers.md,安装与依赖下限见 docs/installation.md,打包元数据见 pyproject.toml,外部工具的探测与执行见 src/ocrmypdf/_exec/,Windows 注册表发现逻辑见 src/ocrmypdf/subprocess/_windows.py,补全脚本见 misc/completion/。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00