Python PDFライブラリとの比較
PDF OxideをPyMuPDF(fitz)、pypdfium2、pypdf、pdfplumber、pdfminerなどと比較します。このページでは、テキスト抽出に適したPython PDFライブラリを選ぶための、パフォーマンス、機能の網羅性、ライセンス、APIの違いを解説します。
サマリー
| PDF Oxide | PyMuPDF | pypdfium2 | pypdf | pdfplumber | pdfminer | |
|---|---|---|---|---|---|---|
| 平均抽出時間 | 0.8ms | 4.6ms | 4.1ms | 12.1ms | 23.2ms | 16.8ms |
| 成功率(3,830件のPDF) | 100% | 99.3% | 99.2% | 98.4% | 98.8% | 98.8% |
| ライセンス | MIT | AGPL-3.0 | Apache-2.0 | BSD-3 | MIT | MIT |
| 言語 | Rust + PyO3 | C (MuPDF) | C (PDFium) | Pure Python | Pure Python | Pure Python |
| テキスト抽出 | あり | あり | あり | あり | あり | あり |
| 文字位置 | あり | あり | あり | 一部 | あり | あり |
| 画像抽出 | あり | あり | あり | あり | なし | なし |
| フォームフィールド | 読み込み + 書き込み | 読み込み + 書き込み | 読み込みのみ | 読み込み + 書き込み | 読み込みのみ | なし |
| PDF作成 | あり | あり | なし | 制限付き | なし | なし |
| PDF編集 | あり | あり | なし | あり | なし | なし |
| Markdown出力 | あり | なし | なし | なし | なし | なし |
| HTML出力 | あり | なし | なし | なし | なし | なし |
| 暗号化 | 読み込み + 書き込み | 読み込み + 書き込み | 読み込みのみ | 読み込み + 書き込み | なし | なし |
| PDF/A検証 | あり | なし | なし | なし | なし | なし |
| レンダリング | あり | あり | あり | なし | なし | なし |
| 検索 | 正規表現 + 空間検索 | あり | あり | なし | なし | なし |
| Pythonバージョン | 3.8–3.14 | 3.8–3.12 | 3.8+ | 3.6+ | 3.8+ | 3.6+ |
| インストールサイズ | 約5 MB(wheel) | 約20 MB(wheel) | 約3 MB(wheel) | 約1 MB | 約1 MB | 約1 MB |
パフォーマンス比較
PDF1件あたりの平均テキスト抽出時間を、3,830件のPDFからなるフルコーパスでベンチマークしました。これは公開されている3つの独立したテストスイートで構成され、すべてのPDF仕様バージョン(1.0〜2.0)、暗号化ファイル、不正な形式のドキュメント、CJKエンコーディング、複雑なレイアウト、セキュリティのエッジケースを網羅しています。各スイートが何をテストし、なぜこれらの結果が再現可能なのかについては、コーパスの詳細をご覧ください。
| ライブラリ | 平均 | 相対値 | p99 | 成功率 |
|---|---|---|---|---|
| PDF Oxide | 0.8ms | 1× | 9ms | 100% |
| PyMuPDF | 4.6ms | 5.8× | 28ms | 99.3% |
| pypdfium2 | 4.1ms | 5.1× | 42ms | 99.2% |
| pymupdf4llm | 55.5ms | 69× | 280ms | 99.1% |
| pdftext | 7.3ms | 9.1× | 82ms | 99.0% |
| pdfminer | 16.8ms | 21× | 124ms | 98.8% |
| pdfplumber | 23.2ms | 29× | 189ms | 98.8% |
| markitdown | 108.8ms | 136× | 378ms | 98.6% |
| pypdf | 12.1ms | 15.1× | 97ms | 98.4% |
PDF Oxideは、PyO3を介してPython拡張モジュールにコンパイルされたネイティブなRustコアによってこの速度を実現しています。サブプロセスのオーバーヘッドやCライブラリの橋渡しは一切なく、Rustコードはプロセス内で直接実行されます。
信頼性
PDF Oxideは3,823件中3,823件の有効なPDFを失敗なく処理します。つまり成功率100%です。3,830件のコーパスのうち成功しなかった7件は、意図的に破損させたテスト用フィクスチャ(PDFヘッダーの欠落、ファジングで破損したカタログ、不正なxrefストリーム)です。
| ライブラリ | 成功した有効なPDF | 成功率 |
|---|---|---|
| PDF Oxide | 3,823 / 3,823 | 100% |
| PyMuPDF | 3,796 / 3,823 | 99.3% |
| pypdfium2 | 3,792 / 3,823 | 99.2% |
| pymupdf4llm | 3,787 / 3,823 | 99.1% |
| pdftext | 3,784 / 3,823 | 99.0% |
| pdfminer | 3,777 / 3,823 | 98.8% |
| pdfplumber | 3,777 / 3,823 | 98.8% |
| markitdown | 3,771 / 3,823 | 98.6% |
| pypdf | 3,762 / 3,823 | 98.4% |
テキスト品質
PDF Oxideは、フルコーパス全体でPyMuPDFおよびpypdfium2と比較して99.5%のテキスト一致率を達成しています。品質は、抽出されたテキスト出力を1文字ずつ比較して測定しました。残りの0.5%の差は、空白の正規化とリガチャの処理によるもので、PDF Oxideはよりクリーンな出力を生成します。
ライセンス比較
| ライブラリ | ライセンス | 商用利用 | コピーレフト |
|---|---|---|---|
| PDF Oxide | MIT | 無制限 | なし |
| pypdfium2 | Apache-2.0 | 無制限 | なし |
| PyMuPDF | AGPL-3.0 | 商用ライセンスが必要(有料) | あり |
| pypdf | BSD-3 | 無制限 | なし |
| pdfplumber | MIT | 無制限 | なし |
| pdfminer | MIT | 無制限 | なし |
| pdftext | GPL-3.0 | オープンソース化が必要 | あり |
PyMuPDFはAGPL-3.0ライセンスのMuPDFを使用しています。PyMuPDFを利用するソフトウェアを配布する場合、そのソフトウェアもAGPL-3.0でリリースするか、Artifexから商用ライセンスを購入する必要があります。これはSaaS製品、Webアプリケーション、および配布されるすべてのバイナリに適用されます。
PDF OxideはMITライセンスで、制限はありません。ライセンス上の義務を一切負うことなく、プロプライエタリ製品、SaaSプラットフォーム、クローズドソースアプリケーションで利用できます。
| ユースケース | PDF Oxide (MIT) | PyMuPDF (AGPL) | pypdfium2 (Apache) | pypdf (BSD) | pdfplumber (MIT) | pdfminer (MIT) |
|---|---|---|---|---|---|---|
| 商用製品 | 可 | ライセンスが必要 | 可 | 可 | 可 | 可 |
| クローズドソース | 可 | 不可(ライセンスがある場合を除く) | 可 | 可 | 可 | 可 |
| SaaS/クラウド | 可 | ライセンスが必要 | 可 | 可 | 可 | 可 |
| 社内ツール | 可 | 可 | 可 | 可 | 可 | 可 |
API比較
テキスト抽出
PDF Oxide:
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
text = doc.extract_text(0)
print(text)
PyMuPDF:
import fitz
doc = fitz.open("report.pdf")
page = doc[0]
text = page.get_text()
print(text)
pypdf:
from pypdf import PdfReader
reader = PdfReader("report.pdf")
page = reader.pages[0]
text = page.extract_text()
print(text)
pdfplumber:
import pdfplumber
with pdfplumber.open("report.pdf") as pdf:
page = pdf.pages[0]
text = page.extract_text()
print(text)
pdfminer:
from pdfminer.high_level import extract_text
text = extract_text("report.pdf", page_numbers=[0])
print(text)
文字単位の抽出
PDF Oxide:
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
chars = doc.extract_chars(0)
for ch in chars:
print(f"'{ch.char}' at ({ch.bbox[0]:.1f}, {ch.bbox[1]:.1f}) "
f"size={ch.font_size:.1f}")
PyMuPDF:
import fitz
doc = fitz.open("report.pdf")
page = doc[0]
blocks = page.get_text("dict")["blocks"]
for block in blocks:
if "lines" in block:
for line in block["lines"]:
for span in line["spans"]:
print(f"'{span['text']}' size={span['size']:.1f}")
pdfplumber:
import pdfplumber
with pdfplumber.open("report.pdf") as pdf:
page = pdf.pages[0]
for char in page.chars:
print(f"'{char['text']}' at ({char['x0']:.1f}, {char['top']:.1f}) "
f"size={char['size']:.1f}")
pdfminer:
from pdfminer.high_level import extract_pages
from pdfminer.layout import LTChar
for page_layout in extract_pages("report.pdf"):
for element in page_layout:
if hasattr(element, '__iter__'):
for text_line in element:
if hasattr(text_line, '__iter__'):
for char in text_line:
if isinstance(char, LTChar):
print(f"'{char.get_text()}' at ({char.x0:.1f}, {char.y0:.1f}) "
f"size={char.size:.1f}")
画像抽出
PDF Oxide:
from pdf_oxide import PdfDocument
doc = PdfDocument("report.pdf")
images = doc.extract_image_bytes(0)
for i, img in enumerate(images):
with open(f"image_{i}.{img['format']}", "wb") as f:
f.write(img["data"])
PyMuPDF:
import fitz
doc = fitz.open("report.pdf")
page = doc[0]
for i, img in enumerate(page.get_images()):
xref = img[0]
base_image = doc.extract_image(xref)
with open(f"image_{i}.{base_image['ext']}", "wb") as f:
f.write(base_image["image"])
pypdf:
from pypdf import PdfReader
reader = PdfReader("report.pdf")
page = reader.pages[0]
for i, image in enumerate(page.images):
with open(f"image_{i}.{image.name.split('.')[-1]}", "wb") as f:
f.write(image.data)
PDF作成
PDF Oxide:
from pdf_oxide import Pdf
pdf = Pdf.from_markdown("# Hello World\n\nThis is a PDF.")
pdf.save("output.pdf")
# Also supports HTML
pdf = Pdf.from_html("<h1>Hello</h1><p>World</p>")
pdf.save("output.pdf")
PyMuPDF:
import fitz
doc = fitz.open()
page = doc.new_page()
text_point = fitz.Point(72, 72)
page.insert_text(text_point, "Hello World", fontsize=24)
doc.save("output.pdf")
pypdf:
# pypdf can merge/modify PDFs but cannot create from scratch with text content.
# Use reportlab or fpdf2 for creation, then merge with pypdf.
暗号化されたPDF
PDF Oxide:
from pdf_oxide import PdfDocument
doc = PdfDocument("encrypted.pdf", password="password")
text = doc.extract_text(0)
PyMuPDF:
import fitz
doc = fitz.open("encrypted.pdf")
doc.authenticate("password")
page = doc[0]
text = page.get_text()
pypdf:
from pypdf import PdfReader
reader = PdfReader("encrypted.pdf")
reader.decrypt("password")
text = reader.pages[0].extract_text()
MarkdownおよびHTML出力
PDF Oxide(独自機能):
from pdf_oxide import PdfDocument
doc = PdfDocument("paper.pdf")
# Convert to Markdown with heading detection
md = doc.to_markdown(0, detect_headings=True)
print(md)
# Convert to HTML
html = doc.to_html(0)
print(html)
組み込みのMarkdownまたはHTML変換を提供するPython PDFライブラリは、他にありません。
ライブラリのプロフィール
PDF Oxide
強み:
- Rustコアによりベンチマークで最速のテキスト抽出 — PyMuPDFより5.8倍高速
- 3,830件のPDFコーパスで100%の成功率 — テストしたどのライブラリよりも高い信頼性
- 抽出、作成、編集を1つのライブラリで扱える統一されたAPI
- 見出し検出に対応した組み込みのMarkdownおよびHTMLエクスポート
- コピーレフトの制限がないMITライセンス
- ネイティブな準拠検証(PDF/A、PDF/UA、PDF/X)
- 主要なすべてのプラットフォームとPython 3.8–3.14向けのビルド済みwheel
- システム依存関係なし — wheelにすべてが含まれています
制限:
- 比較的新しいライブラリで、コミュニティが小規模
- テーブル抽出は、pdfplumberのアルゴリズムと比べると基本的
- レンダリングエンジンはMuPDFほど成熟していない
PyMuPDF (fitz)
強み:
- 成熟し、実戦で鍛えられている(MuPDFが基盤で、2005年から開発が続く)
- 複雑なPDFに対する優れたレンダリング品質
- 組み込みのOCR連携(Tesseract)
- 豊富な機能セット:SVGエクスポート、ページ操作、テーブル検出
制限:
- AGPL-3.0ライセンスにより、アプリケーションのオープンソース化または商用ライセンスの購入が必要
- バンドルされたMuPDFにより、wheelサイズが大きい(約20 MB)
- 組み込みのMarkdownエクスポートなし
- 準拠検証なし
pypdfium2
強み:
- 高速(GoogleのPDFiumエンジンが基盤)
- Apache-2.0ライセンス — 商用利用に寛容
- 良好なレンダリング品質
制限:
- PDF OxideやPyMuPDFと比べて限定的なテキスト抽出API
- PDFの作成や編集ができない
- 読み込み専用を超えるフォームフィールドのサポートなし
pypdf
強み:
- Pure Python — どこにでもインストール可能で、コンパイル済みの依存関係なし
- 軽量で、よくメンテナンスされている
- PDF操作(結合、分割、回転、暗号化)に適している
- 大規模なコミュニティと充実したドキュメント
制限:
- テキスト抽出はPDF Oxideより15倍遅い
- 複雑なレイアウトではテキスト抽出品質に難がある
- レンダリング、Markdown/HTMLエクスポート、テーブル抽出なし
pdfplumber
強み:
- Python PDFライブラリの中で最も優れたテーブル抽出
- 優れた文字単位の位置情報データ
- 視覚的なデバッグツール(注釈付きのページ画像)
- MITライセンス
制限:
- Pure Python — PDF Oxideより29倍遅い
- 読み込み専用 — PDFの作成や編集ができない
- 暗号化やレンダリングなし
pdfminer
強み:
- 詳細な文字およびレイアウト解析
- 良好なCJKテキストサポート
- pdfplumberや他のツールの基盤
- MITライセンス
制限:
- PDF Oxideより21倍遅い(Pure Pythonで未最適化)
- 読み込み専用で、作成や編集ができない
- 一般的なタスクに対して冗長なAPI
- メンテナンスがあまり活発でない
どれを使うべきか
| ユースケース | 推奨ライブラリ |
|---|---|
| 高速なテキスト抽出 | PDF Oxide |
| 商用・プロプライエタリ製品 | PDF Oxide、pypdfium2、pypdf、pdfplumber、またはpdfminer |
| PyMuPDFの代替(MITライセンス) | PDF Oxide |
| Markdown/HTMLからのPDF作成 | PDF Oxide |
| 準拠検証(PDF/A、PDF/X) | PDF Oxide |
| 請求書からのテーブル抽出 | pdfplumber |
| 抽出結果の視覚的なデバッグ | pdfplumber |
| 既存のMuPDF資産がある | PyMuPDF(AGPLと互換性がある場合) |
| 最小限の依存関係 | pypdf(Pure Python) |
| 詳細なレイアウト解析 | pdfminer |
| スキャンされたドキュメントのOCR | PyMuPDF |
インストール
# PDF Oxide
pip install pdf_oxide
# PyMuPDF
pip install pymupdf
# pypdfium2
pip install pypdfium2
# pypdf
pip install pypdf
# pdfplumber
pip install pdfplumber
# pdfminer
pip install pdfminer.six
PDF Oxideは、Linux(x86_64、aarch64)、macOS(x86_64、arm64)、Windows(x86_64)向けのビルド済みwheelを提供します。コンパイラやシステムライブラリは不要です。
関連ページ
- パフォーマンスベンチマーク – フルコーパスのベンチマーク結果
- Pythonでの導入 – インストールと最初の抽出
- Python APIリファレンス – 完全なPython API
- Rust PDFライブラリとの比較 – Rustエコシステムの比較