PDF Oxide をはじめよう(Objective-C)
PDF Oxide は Rust コアの上にイディオマティックな Objective-C バインディングを提供します。テキスト抽出は平均 0.8ms、3,830 件の PDF で合格率 100% を達成しています。NSObject ラッパー(POXDocument、POXPdf)がネイティブハンドルを所有し、ARC のもとで解放します。返却される文字列は NSString として戻り、C ABI のエラーコードはすべて POXErrorDomain の NSError として表面化します。v0.3.69 で新登場。
インストール
Objective-C バインディングはデフォルトフィーチャーの cdylib をリンクし、ARC のもとで clang でビルドします。まずネイティブライブラリをビルドし、それに対して make build を実行します。
# 1. ネイティブライブラリをビルド(バインディング同梱のフィーチャーセット)
cargo build --release --lib --features ocr,rendering,signatures,barcodes,tsa-client,system-fonts
# 2. Objective-C バインディングをビルド(clang、ARC)
cd objc
make build PDF_OXIDE_LIB_DIR="$PWD/../target/release"
DYLD_LIBRARY_PATH="$PWD/../target/release" ./basic_extraction
ソースでは単一の公開ヘッダーをインポートします。
#import "POXPdfOxide.h"
クイックスタート
PDF を開き、メタデータを確認し、最初のページからテキストを抽出します。失敗する可能性のある呼び出しはすべて、末尾に NSError** を取ります。
#import "POXPdfOxide.h"
NSError *err = nil;
POXDocument *doc = [POXDocument openPath:@"research-paper.pdf" error:&err];
if (!doc) {
NSLog(@"open failed: %@", err.localizedDescription);
return;
}
NSInteger pages = [doc pageCountError:&err];
POXVersion ver = [doc version];
NSLog(@"pages: %ld version: %d.%d", (long)pages, ver.major, ver.minor);
NSString *text = [doc extractText:0 error:&err];
NSLog(@"%@", text);
メモリ上のバイト列から開くこともできます。PDF がネットワーク経由やデータベースから届く場合に便利です。また、パスワード保護されたファイルを開くこともできます。
POXDocument *doc = [POXDocument openFromBytes:pdfData error:&err];
// 暗号化されたドキュメントを、最初からパスワードを渡して開く:
POXDocument *enc = [POXDocument openWithPassword:@"confidential.pdf"
password:@"secret"
error:&err];
// または開いた後で認証する:
BOOL ok = [doc authenticate:@"secret" error:&err];
テキスト抽出
プレーンテキストが最速の経路です。0 始まりのインデックスで 1 ページだけを抽出することも、ドキュメント全体を一度に取得することもできます。
// 1 ページ
NSString *text = [doc extractText:0 error:&err];
// ドキュメント全体を連結
NSString *all = [doc toPlainTextAllWithError:&err];
// ページごとに
NSInteger count = [doc pageCountError:&err];
for (NSInteger i = 0; i < count; i++) {
NSLog(@"--- page %ld ---\n%@", (long)i, [doc extractText:i error:&err]);
}
単語と行
extractWords: と extractTextLines: は、バウンディングボックスとフォントメタデータを備えた要素オブジェクトの配列を返します。いずれも PDF ユーザー空間のポイント単位です。
NSArray<POXWord *> *words = [doc extractWords:0 error:&err];
for (POXWord *w in words) {
POXBbox box = w.bbox;
NSLog(@"'%@' at (%.1f, %.1f) %.1fx%.1f font=%@ size=%.1f bold=%d",
w.text, box.x, box.y, box.width, box.height,
w.fontName, w.fontSize, w.bold);
}
NSArray<POXTextLine *> *lines = [doc extractTextLines:0 error:&err];
for (POXTextLine *line in lines) {
NSLog(@"%@ (%ld words)", line.text, (long)line.wordCount);
}
POXChar(extractChars: で取得)は、文字単位で同じ構造を公開します — character、bbox、fontName、fontSize です。
Markdown と HTML
ページ単位、またはドキュメント全体を Markdown や HTML に変換します。
// 単一ページ
NSString *md = [doc toMarkdown:0 error:&err];
NSString *html = [doc toHtml:0 error:&err];
// ドキュメント全体
NSString *mdAll = [doc toMarkdownAllWithError:&err];
NSString *htmlAll = [doc toHtmlAllWithError:&err];
検索
search:term:caseSensitive:error: で単一ページを、searchAll:caseSensitive:error: でドキュメント全体を検索します。どちらも、一致したテキスト、ページインデックス、バウンディングボックスを保持する POXSearchResult の配列を返します。
NSArray<POXSearchResult *> *hits =
[doc searchAll:@"configuration" caseSensitive:NO error:&err];
for (POXSearchResult *r in hits) {
POXBbox b = r.bbox;
NSLog(@"page %ld: '%@' at (%.0f, %.0f)", (long)r.page, r.text, b.x, b.y);
}
// 単一ページ版:
NSArray<POXSearchResult *> *pageHits =
[doc search:0 term:@"configuration" caseSensitive:NO error:&err];
PDF の生成
POXPdf ビルダーは、Markdown、HTML、プレーンテキストから PDF を生成します。パスに保存することも、NSData としてバイト列を取得することもできます。
POXPdf *pdf = [POXPdf fromMarkdown:@"# Hello World\n\nThis is a PDF.\n"
error:&err];
[pdf saveToPath:@"output.pdf" error:&err];
// またはバイト列をメモリに保持
NSData *bytes = [pdf toBytesWithError:&err];
// HTML とプレーンテキスト用のコンストラクタもあります
POXPdf *invoice = [POXPdf fromHtml:@"<h1>Invoice</h1><p>Amount: $42</p>"
error:&err];
POXPdf *notes = [POXPdf fromText:@"Plain text content." error:&err];
ビルダーからそのままドキュメントへとつなぎ、抽出までを一気に行えます。
POXPdf *pdf = [POXPdf fromMarkdown:@"# Report\n\nBody text.\n" error:&err];
POXDocument *doc = [POXDocument openFromBytes:[pdf toBytesWithError:&err]
error:&err];
NSLog(@"%@", [doc extractText:0 error:&err]);
エラー処理
失敗する可能性のあるメソッドはすべて、末尾の NSError** に書き込み、失敗時には nil またはセンチネル値を返します。エラーは POXErrorDomain に属します。
NSError *err = nil;
POXDocument *doc = [POXDocument openPath:@"document.pdf" error:&err];
if (!doc) {
if ([err.domain isEqualToString:POXErrorDomain]) {
NSLog(@"PDF error: %@", err.localizedDescription);
}
return;
}
NSString *text = [doc extractText:0 error:&err];
if (!text) {
NSLog(@"extract failed: %@", err.localizedDescription);
}
ハンドルは ARC のもとで自動的に解放されますが、-close(冪等)でネイティブハンドルを早期に解放することもできます。
[doc close];
次のステップ
- Rust クイックスタート — Rust から PDF Oxide を使う
- Python クイックスタート — Python から PDF Oxide を使う
- テキスト抽出 — 抽出オプションとレシピの詳細
- PDF 生成 — ビルダー API による高度な生成
- 編集 — 既存 PDF、注釈、フォームフィールドの変更