PDF Oxide をはじめる(C++)
PDF Oxide は、Rust コアの上に構築された、イディオマティックでヘッダオンリーの C++17 バインディングを提供します。テキスト抽出は平均 0.8ms、3,830 件の PDF で 100% のパス率を達成しています。ハンドルはムーブ専用の RAII ラッパーで、ネイティブの文字列やバッファは std::string / std::vector<std::uint8_t> へ自動的にコピーされ、C ABI のエラーコードは pdf_oxide::Error としてスローされます。v0.3.69 で新登場。
インストール
バインディングは単一のヘッダ(cpp/include/pdf_oxide/pdf_oxide.hpp)で、ネイティブの cdylib にリンクします。まずリポジトリのルートでライブラリを一度ビルドし、その後 CMake にその場所を指定します。
# 1. build the native library (shipped binding feature set)
cargo build --release --lib \
--features ocr,rendering,signatures,barcodes,tsa-client,system-fonts
# 2. configure + build with the header-only wrapper
cmake -S cpp -B cpp/build -DCMAKE_BUILD_TYPE=Release \
-DPDF_OXIDE_LIB_DIR="$PWD/target/release"
cmake --build cpp/build -j
あとは、ご自身の翻訳単位でヘッダをインクルードするだけです。
#include <pdf_oxide/pdf_oxide.hpp>
C ヘッダはグローバルな
using namespace pdf_oxide;は使わないでください。名前は修飾して書く(pdf_oxide::Pdf、pdf_oxide::Document)か、必要なものだけをusing宣言で取り込んでください。
クイックスタート
PDF を開き、ページから読み取り順のテキストを抽出します。失敗しうる呼び出しはすべて pdf_oxide::Error をスローするので、処理は try/catch で囲んでください。
#include <pdf_oxide/pdf_oxide.hpp>
#include <iostream>
int main() {
try {
auto doc = pdf_oxide::Document::open("research-paper.pdf");
std::cout << "pages: " << doc.page_count() << "\n";
pdf_oxide::Version v = doc.version();
std::cout << "version: " << static_cast<int>(v.major) << "."
<< static_cast<int>(v.minor) << "\n";
std::string text = doc.extract_text(0); // 0-based page index
std::cout << text << "\n";
return 0;
} catch (const pdf_oxide::Error& e) {
std::cerr << "error: " << e.what() << "\n";
return 1;
}
}
すでにメモリ上にある PDF を開くには、Document::open_from_bytes を使います。
std::vector<std::uint8_t> bytes = load_pdf_bytes(); // from S3, HTTP, a DB…
auto doc = pdf_oxide::Document::open_from_bytes(bytes);
std::string text = doc.extract_text(0);
Markdown・HTML への変換
単一ページ、あるいはドキュメント全体を Markdown または HTML に変換できます。
auto doc = pdf_oxide::Document::open("paper.pdf");
std::string page_md = doc.to_markdown(0); // one page
std::string all_md = doc.to_markdown_all(); // every page
std::string page_html = doc.to_html(0);
std::string all_html = doc.to_html_all();
std::cout << all_md << "\n";
単語単位の抽出
extract_words(page_index) は std::vector<pdf_oxide::Word> を返し、ページ上のすべての単語についてテキスト・バウンディングボックス・フォントのメタデータを含みます。
auto doc = pdf_oxide::Document::open("paper.pdf");
auto words = doc.extract_words(0);
for (const auto& w : words) {
std::cout << "'" << w.text << "'"
<< " at (" << w.bbox.x << ", " << w.bbox.y << ")"
<< " size=" << w.font_size
<< " font=" << w.font_name
<< (w.bold ? " [bold]" : "") << "\n";
}
pdf_oxide::Word のフィールド:
| フィールド | 型 | 説明 |
|---|---|---|
text |
std::string |
単語のテキスト |
bbox |
Bbox |
バウンディングボックス(x、y、width、height) |
font_name |
std::string |
PostScript フォント名 |
font_size |
float |
フォントサイズ(ポイント単位) |
bold |
bool |
そのランが太字かどうか |
文字単位・行単位の抽出も同じ形をとります。extract_chars(0) は Char レコード(Unicode コードポイント + bbox)を返し、extract_text_lines(0) は TextLine レコード(text、bbox、word_count)を返します。
検索
単一ページの検索には search(page_index, term, case_sensitive) を、ドキュメント全体の検索には search_all(term, case_sensitive) を使います。いずれも std::vector<pdf_oxide::SearchResult> を返します。
auto doc = pdf_oxide::Document::open("manual.pdf");
// One page
auto hits = doc.search(0, "configuration", /*case_sensitive=*/false);
// Every page
auto all_hits = doc.search_all("configuration", /*case_sensitive=*/false);
for (const auto& r : all_hits) {
std::cout << "page " << r.page << ": '" << r.text << "'"
<< " at (" << r.bbox.x << ", " << r.bbox.y << ")\n";
}
PDF の作成
pdf_oxide::Pdf ビルダーは、Markdown・HTML・プレーンテキストからドキュメントを作成します。to_bytes() でシリアライズするか、save() でディスクへ直接書き出します。
// From Markdown
auto pdf = pdf_oxide::Pdf::from_markdown("# Hello World\n\nThis is a PDF.\n");
pdf.save("output.pdf");
// From HTML
auto invoice = pdf_oxide::Pdf::from_html("<h1>Invoice</h1><p>Amount: $42</p>");
invoice.save("invoice.pdf");
// From plain text, or grab the bytes for in-memory use
auto notes = pdf_oxide::Pdf::from_text("Plain text body.");
std::vector<std::uint8_t> bytes = notes.to_bytes();
作成したばかりの PDF を、そのまま Document に往復させることもできます。
auto pdf = pdf_oxide::Pdf::from_markdown("# Title\n\nbody\n");
auto doc = pdf_oxide::Document::open_from_bytes(pdf.to_bytes());
std::cout << doc.to_markdown_all() << "\n";
エラーハンドリング
失敗しうる操作はすべて pdf_oxide::Error をスローします。これはネイティブのエラーメッセージ(what())と生の C ABI エラーコード(code())を保持します。また、ハンドルは明示的にクローズ可能で、冪等です。doc.close() はネイティブハンドルを早期に解放し、クローズ後に使用するとスローされます。
#include <pdf_oxide/pdf_oxide.hpp>
#include <iostream>
int main() {
try {
auto doc = pdf_oxide::Document::open("missing.pdf");
std::cout << doc.extract_text(0) << "\n";
doc.close(); // optional — happens automatically at scope exit
} catch (const pdf_oxide::Error& e) {
std::cerr << "pdf error (" << e.code() << "): " << e.what() << "\n";
return 1;
}
}
次のステップ
- Rust をはじめる – Rust から PDF Oxide を使う
- Python をはじめる – Python から PDF Oxide を使う
- テキスト抽出 – 抽出オプションとレシピの詳細
- PDF の作成 – メタデータや暗号化を伴う高度な作成
- 編集 – 既存 PDF・注釈・フォームフィールドの編集