2026 最佳 Rust PDF crate 对比
PDF Oxide 与 Rust 生态中最常用的 PDF crate 正面对比:lopdf、printpdf、pdf-rs、pdf_extract。每个 crate 定位的抽象层级与使用场景不同——本页帮你为当前项目选出合适的 crate。
总结
| PDF Oxide | lopdf | printpdf | pdf-rs | pdf_extract | |
|---|---|---|---|---|---|
| API 层级 | 高级 | 底层 | 中级(创建) | 底层(读取) | 中级(读取) |
| 读取 PDF | 支持 | 支持 | 不支持 | 支持 | 支持 |
| 写入 PDF | 支持 | 支持 | 支持 | 不支持 | 不支持 |
| 文本提取 | 支持(高级) | 手动 | 不支持 | 手动 | 支持(基础) |
| 图片提取 | 支持(高级) | 手动 | 不支持 | 手动 | 不支持 |
| 表单字段 | 读写 | 手动 | 不支持 | 只读 | 不支持 |
| PDF 创建 | 支持 | 支持 | 支持 | 不支持 | 不支持 |
| Markdown/HTML 输入 | 支持 | 不支持 | 不支持 | 不支持 | 不支持 |
| 编辑现有 PDF | 支持 | 支持(底层) | 不支持 | 不支持 | 不支持 |
| 注释 | 读写 | 手动 | 不支持 | 只读 | 不支持 |
| 加密 | 读写 | 不支持 | 不支持 | 不支持 | 不支持 |
| PDF/A 验证 | 支持 | 不支持 | 不支持 | 不支持 | 不支持 |
| 渲染 | 支持(tiny-skia) | 不支持 | 不支持 | 部分 | 不支持 |
| Python 绑定 | 支持 | 不支持 | 不支持 | 不支持 | 不支持 |
| 许可证 | MIT | MIT | MIT | MIT | Apache-2.0 |
所有库都采用宽松许可证。差异在于功能范围和抽象层级。
性能对比
完整语料库基准测试(3,830 个 PDF)
在完整的 3,830 个 PDF 语料库上测试——包含三个独立的公开测试集,覆盖 PDF 规范合规性(veraPDF,2,907 个文件)、真实世界浏览器渲染边界情况(Mozilla pdf.js,897 个文件)和安全/健壮性压力测试,包括格式错误的结构和模糊测试生成的损坏(DARPA SafeDocs,26 个文件)。参见完整语料库详情。
| 库 | 平均 | p99 | 通过率 | 文本提取 | 备注 |
|---|---|---|---|---|---|
| PDF Oxide | 0.8ms | 9ms | 100% | 内置,生产级 | Unicode、CJK、阅读顺序 |
| oxidize_pdf | 13.5ms | 11ms | 99.1% | 基础 | 48 秒最大异常值 |
| unpdf | 2.8ms | 10ms | 95.1% | 基础 | 完整语料库 185 个失败 |
| pdf_extract | 4.08ms | 37ms | 91.5% | 基础 | 缺少复杂布局支持 |
| lopdf | 0.3ms | 2ms | 80.2% | 无内置提取 | 20% 的 PDF 解析失败 |
lopdf 在它能解析的 PDF 上更快——但它在 20% 的语料库上失败,且不提供文本提取。你需要自己构建字体解码、CMap 解析和间距分析。
pdf_extract 提供基础文本提取但通过率为 91.5%,在复杂布局、CJK 文本和带标签的 PDF 上表现不佳。oxidize_pdf 有不错的可靠性(99.1%)但平均提取时间比 pdf_oxide 慢 17 倍,且最坏情况达 48 秒。unpdf 能处理完整语料库但在 185 个 PDF 上失败。
PDF Oxide 是唯一将 100% 可靠性与生产级文本提取相结合的 Rust crate。
API 设计对比
PDF Oxide:高级、面向任务
PDF Oxide 提供面向常见任务的专用方法。你直接操作文本、图片和表单字段——而非 PDF 对象和字典。
use pdf_oxide::PdfDocument;
let mut doc = PdfDocument::open("report.pdf")?;
// 文本提取——一次调用
let text = doc.extract_text(0)?;
println!("{}", text);
// 带字体元数据的样式 span
let spans = doc.extract_spans(0)?;
for span in &spans {
println!("'{}' font={} size={:.1}pt", span.text, span.font_name, span.font_size);
}
// 图片提取
let images = doc.extract_images(0)?;
for img in &images {
println!("{}x{} {:?}", img.width, img.height, img.format);
}
// 表单字段
let fields = doc.extract_form_fields()?;
for field in &fields {
println!("{}: {:?}", field.name, field.value);
}
PDF 创建同样简洁:
use pdf_oxide::api::Pdf;
// 从 Markdown
let pdf = Pdf::from_markdown("# Report\n\n| A | B |\n|---|---|\n| 1 | 2 |")?;
pdf.save("report.pdf")?;
// 从 HTML
let pdf = Pdf::from_html("<h1>Report</h1><p>Content here.</p>")?;
pdf.save("report.pdf")?;
lopdf:底层对象操作
lopdf 让你直接访问 PDF 对象、流和交叉引用表。你必须理解 PDF 规范才能有效使用它。没有内置文本提取——你需要自己遍历字典并解码流。
use lopdf::Document;
let doc = Document::load("report.pdf")?;
// 获取页面字典
let page_id = doc.page_iter().next().unwrap();
let page = doc.get_dictionary(page_id)?;
// 获取内容流——手动操作
let contents = page.get("Contents")?;
let stream = doc.get_object(contents.as_reference()?)?;
// 要提取文本你必须:
// 1. 解析内容流操作符
// 2. 从 /Resources 解析字体引用
// 3. 解码 CMap/ToUnicode 映射
// 4. 应用文本矩阵变换
// 5. 处理编码差异
//
// lopdf 不提供这些——它只是原始对象访问
println!("Page has {} objects", doc.objects.len());
lopdf 适合需要直接操作 PDF 结构的场景:合并文档、重写对象流或构建专用 PDF 处理器。
printpdf:仅限 PDF 创建
printpdf 是一个仅用于创建的库。它不能读取或解析现有 PDF。它提供类型化 API 用于从零构建 PDF 文档,支持文本、图片和矢量图形。
use printpdf::*;
let (doc, page1, layer1) = PdfDocument::new(
"Report", Mm(210.0), Mm(297.0), "Layer 1"
);
let current_layer = doc.get_page(page1).get_layer(layer1);
// 添加文本——需要手动加载字体
let font = doc.add_builtin_font(BuiltinFont::Helvetica)?;
current_layer.use_text("Hello World", 24.0, Mm(10.0), Mm(280.0), &font);
// 保存
doc.save(&mut std::io::BufWriter::new(
std::fs::File::create("output.pdf")?,
))?;
// 无法读取现有 PDF
// 无法提取文本、图片或表单字段
printpdf 适合只需要生成新 PDF 且需要干净的专用创建 API 的场景。
pdf-rs:底层 PDF 读取
pdf-rs 将 PDF 结构解析为 Rust 类型,但提供的高级功能极少。你可以获得对 PDF 对象的类型安全访问,但仍需自己处理文本解码、字体解析和内容流解析。
use pdf::file::FileOptions;
let file = FileOptions::cached().open("report.pdf")?;
// 访问页面对象
let page = file.get_page(0)?;
let media_box = page.media_box()?;
println!("Page size: {:?}", media_box);
// 内容流访问——底层
if let Some(ref contents) = page.contents {
// 返回原始操作——你必须自己解释
// 无内置文本组装、字体解码或布局分析
}
// 无法写入或修改 PDF
pdf-rs 适合需要类型安全的 PDF 解析器用于分析、验证或构建自定义渲染器的场景。
按任务的功能对比
文本提取
| 库 | 内置 | 质量 | 需要的工作量 |
|---|---|---|---|
| PDF Oxide | 支持 | 生产级(Unicode、CJK、阅读顺序) | 一次方法调用 |
| pdf_extract | 支持 | 基础(缺少复杂布局) | 一次方法调用 |
| lopdf | 不支持 | 无 | 数百行自定义代码 |
| printpdf | 不支持 | 无 | 不可能(只写) |
| pdf-rs | 不支持 | 无 | 需要大量自定义代码 |
PDF Oxide 处理 CMap/ToUnicode 解码、基于字体度量的间距、结构树阅读顺序和连字重建。在 lopdf 或 pdf-rs 之上实现等效功能需要数千行代码和深入的 PDF 规范知识。
PDF 创建
| 库 | 方式 | Markdown/HTML 输入 | 表格 | 条码 |
|---|---|---|---|---|
| PDF Oxide | 高级 + 底层 | 支持 | 支持 | 支持 |
| lopdf | 原始对象构建 | 不支持 | 不支持 | 不支持 |
| printpdf | 类型化图层 API | 不支持 | 不支持 | 不支持 |
| pdf-rs | 无(只读) | 无 | 无 | 无 |
加密
| 库 | 读取加密 | 写入加密 | 算法 |
|---|---|---|---|
| PDF Oxide | 支持 | 支持 | RC4-40、RC4-128、AES-128、AES-256 |
| lopdf | 不支持 | 不支持 | – |
| printpdf | 不支持 | 不支持 | – |
| pdf-rs | 部分 | 不支持 | 仅 RC4 |
合规性
| 库 | PDF/A | PDF/X | PDF/UA |
|---|---|---|---|
| PDF Oxide | 验证 + 转换 | 验证 | 验证 |
| lopdf | 不支持 | 不支持 | 不支持 |
| printpdf | 部分(PDF/A-1b 输出) | 不支持 | 不支持 |
| pdf-rs | 不支持 | 不支持 | 不支持 |
依赖足迹
| 库 | 依赖数 | 编译时间 | 二进制大小 |
|---|---|---|---|
| PDF Oxide | ~40(核心) | ~30s | ~4 MB |
| lopdf | ~15 | ~10s | ~1 MB |
| printpdf | ~20 | ~15s | ~2 MB |
| pdf-rs | ~25 | ~20s | ~2 MB |
PDF Oxide 的依赖更多是因为它包含字体解析、图片解码、内容流解释和加密——这些功能其他库要么留给用户要么完全省略。启用所有可选功能(rendering、barcodes、office)后,依赖数会增加到 ~100。
组合使用库
由于所有库都采用宽松许可,你可以在同一个项目中组合使用:
[dependencies]
pdf_oxide = "0.3"
lopdf = "0.32" # 可选:用于边界情况的原始对象访问
常见模式:
- PDF Oxide + lopdf:使用 PDF Oxide 做提取和创建,对需要原始对象操作的边界情况回退到 lopdf。
- PDF Oxide + printpdf:使用 PDF Oxide 做读取,printpdf 做专门的创建工作流。
用例矩阵
“我需要从 PDF 提取文本”
| Crate | 适合? | 备注 |
|---|---|---|
| PDF Oxide | 是 | 最佳提取质量、100% 通过率、阅读顺序、字体元数据 |
| pdf_extract | 部分 | 基础提取,91.5% 通过率 |
| lopdf | 否 | 无文本提取 |
| printpdf | 否 | 不能读取 PDF |
| pdf-rs | 部分 | 基础解析,无高级文本提取 |
“我需要创建 PDF”
| Crate | 适合? | 备注 |
|---|---|---|
| PDF Oxide | 是 | 高级(Markdown/HTML)和底层 API |
| lopdf | 部分 | 底层对象构建 |
| printpdf | 是 | 干净的创建 API,不能读取 |
| pdf-rs | 否 | 只读 |
“我需要编辑现有 PDF”
| Crate | 适合? | 备注 |
|---|---|---|
| PDF Oxide | 是 | DOM 式编辑、注释、表单 |
| lopdf | 部分 | 底层对象操作 |
| printpdf | 否 | 不能读取 PDF |
| pdf-rs | 否 | 只读 |
“我需要完整生命周期(提取 + 创建 + 编辑)”
| Crate | 适合? | 备注 |
|---|---|---|
| PDF Oxide | 是 | 唯一覆盖所有三者的 crate |
| lopdf + printpdf | 部分 | 两个 crate,无文本提取 |
| pdf-rs + printpdf | 部分 | 两个 crate,无编辑功能 |
何时使用各库
选择 PDF Oxide: 如果你需要多种 PDF 能力(提取 + 创建,或提取 + 编辑),并且需要一个经过充分测试、100% 可靠的单一依赖。
选择 lopdf: 如果你需要底层 PDF 结构操作,并且愿意直接使用 PDF 规范。适合合并、拆分和批量 PDF 处理。
选择 printpdf: 如果你只创建 PDF 而不需要读取。最干净的报告和文档生成 API。
选择 pdf-rs: 如果你需要一个符合规范的解析器用于 PDF 分析,或者正在构建自己的渲染流水线。
选择 pdf_extract: 如果你需要基础文本提取,且不要求高可靠性或复杂布局支持。
相关页面
- 性能基准测试 – 完整语料库基准测试结果
- Rust 快速入门 – 安装和首次提取
- Rust API 参考 – 完整 Rust API
- vs Python PDF 库 – Python 生态对比