2026 年おすすめ Rust PDF crate 比較
PDF Oxide を主要な Rust PDF crate(lopdf、printpdf、pdf-rs、pdf_extract)と直接比較します。それぞれ抽象化レベルも想定ユースケースも異なるため、このページでは用途に合った 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 ファイル)の 3 つの独立した公開テストスイートで構成。詳細はコーパスの詳細をご覧ください。
| ライブラリ | 平均 | 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% | 内蔵抽出なし | PDF の 20% でパース失敗 |
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 クレートです。
API 設計の比較
PDF Oxide: 高レベル、タスク指向
PDF Oxide は一般的なタスク向けの専用メソッドを提供します。PDF オブジェクトやディクショナリではなく、テキスト、画像、フォームフィールドを扱います。
use pdf_oxide::PdfDocument;
let mut doc = PdfDocument::open("report.pdf")?;
// テキスト抽出 -- 1 回の呼び出し
let text = doc.extract_text(0)?;
println!("{}", text);
// フォントメタデータ付きスタイルスパン
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 の読み取りやパースはできません。テキスト、画像、ベクターグラフィックスで PDF ドキュメントをゼロから構築するための型付き API を提供します。
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, 読み取り順序) | メソッド 1 回の呼び出し |
| pdf_extract | あり | 基本的(複雑なレイアウトの欠落) | メソッド 1 回の呼び出し |
| lopdf | なし | N/A | 数百行のカスタムコード |
| printpdf | なし | N/A | 不可(書き込み専用) |
| pdf-rs | なし | N/A | 大量のカスタムコードが必要 |
PDF Oxide は CMap/ToUnicode デコード、フォントメトリクスベースのスペーシング、構造ツリーの読み取り順序、リガチャ再構成を処理します。lopdf や pdf-rs の上に同等の機能を実装するには数千行のコードと PDF 仕様の深い知識が必要です。
PDF 作成
| ライブラリ | アプローチ | Markdown/HTML 入力 | テーブル | バーコード |
|---|---|---|---|---|
| PDF Oxide | 高レベル + 低レベル | あり | あり | あり |
| lopdf | 生オブジェクト構築 | なし | なし | なし |
| printpdf | 型付きレイヤー API | なし | なし | なし |
| pdf-rs | N/A(読み取り専用) | N/A | N/A | N/A |
暗号化
| ライブラリ | 暗号化読み取り | 暗号化書き込み | アルゴリズム |
|---|---|---|---|
| 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(コア) | ~30 秒 | ~4 MB |
| lopdf | ~15 | ~10 秒 | ~1 MB |
| printpdf | ~20 | ~15 秒 | ~2 MB |
| pdf-rs | ~25 | ~20 秒 | ~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 からテキストを抽出したい」
| クレート | 適切? | 備考 |
|---|---|---|
| PDF Oxide | はい | 最高品質の抽出、100% パス率、読み取り順序、フォントメタデータ |
| pdf_extract | 部分的 | 基本的な抽出、91.5% パス率 |
| lopdf | いいえ | テキスト抽出なし |
| printpdf | いいえ | PDF の読み取り不可 |
| pdf-rs | 部分的 | 基本的なパース、高レベルテキスト抽出なし |
「PDF を作成したい」
| クレート | 適切? | 備考 |
|---|---|---|
| PDF Oxide | はい | 高レベル(Markdown/HTML)と低レベル API |
| lopdf | 部分的 | 低レベルオブジェクト構築 |
| printpdf | はい | クリーンな作成 API、読み取り不可 |
| pdf-rs | いいえ | 読み取り専用 |
「既存の PDF を編集したい」
| クレート | 適切? | 備考 |
|---|---|---|
| PDF Oxide | はい | DOM ライクな編集、注釈、フォーム |
| lopdf | 部分的 | 低レベルオブジェクト操作 |
| printpdf | いいえ | PDF の読み取り不可 |
| pdf-rs | いいえ | 読み取り専用 |
「フルライフサイクル(抽出 + 作成 + 編集)が必要」
| クレート | 適切? | 備考 |
|---|---|---|
| PDF Oxide | はい | 3 つすべてをカバーする唯一のクレート |
| lopdf + printpdf | 部分的 | 2 クレート、テキスト抽出なし |
| pdf-rs + printpdf | 部分的 | 2 クレート、編集なし |
使い分けガイド
PDF Oxide を選ぶ場合: 複数の PDF 機能(抽出 + 作成、または抽出 + 編集)が必要で、100% の信頼性を持つ十分にテストされた単一の依存パッケージが欲しい場合。
lopdf を選ぶ場合: 低レベルの PDF 構造操作が必要で、PDF 仕様を直接扱うことに慣れている場合。結合、分割、バッチ PDF 処理に適しています。
printpdf を選ぶ場合: PDF の作成のみで読み取りが不要な場合。レポートやドキュメント生成に最もクリーンな API。
pdf-rs を選ぶ場合: PDF 分析用の仕様準拠パーサーが必要、またはカスタムレンダリングパイプラインを構築している場合。
pdf_extract を選ぶ場合: 基本的なテキスト抽出が必要で、高い信頼性や複雑なレイアウトサポートは不要な場合。
関連ページ
- パフォーマンスベンチマーク – コーパス全体のベンチマーク結果
- Rust で始める – インストールと最初の抽出
- Rust API リファレンス – 完全な Rust API
- Python PDF ライブラリとの比較 – Python エコシステムの比較