PDF Oxide をはじめる(Java)
PDF Oxide はテキスト抽出において最速の Java PDFライブラリです — 平均0.8ms、実世界の3,830件のPDFで100%の成功率を達成しています。同じ Rust コアが Python、Go、JS、C# にも提供されており、Java バインディングは JDK 11 LTS を下限とする薄い JNI レイヤーで、同じ JAR から Kotlin との相互運用も無償で利用できます。
インストール
この JAR には Linux(x86_64/aarch64)、macOS(x86_64/aarch64)、Windows(x86_64)向けのネイティブライブラリが同梱されています。コンパイラや追加のセットアップは不要で、最初の呼び出し時に適切なライブラリが展開されます。
Maven
<dependency>
<groupId>fyi.oxide</groupId>
<artifactId>pdf-oxide</artifactId>
<version>0.3.69</version>
</dependency>
Gradle
// Kotlin DSL
implementation("fyi.oxide:pdf-oxide:0.3.69")
// Groovy
implementation 'fyi.oxide:pdf-oxide:0.3.69'
クイックスタート
PDF を開いてテキストを抽出します。PdfDocument は AutoCloseable なので、try-with-resources を使ってネイティブハンドルを確実に解放しましょう。
import fyi.oxide.pdf.PdfDocument;
import java.nio.file.Path;
try (PdfDocument doc = PdfDocument.open(Path.of("report.pdf"))) {
System.out.println("Pages: " + doc.pageCount());
System.out.println(doc.extractText(0)); // ページインデックスは0始まり
}
パス文字列、Path、生の byte[]、または InputStream から開くことができます。
import fyi.oxide.pdf.PdfDocument;
byte[] pdfBytes = downloadFromS3();
try (PdfDocument doc = PdfDocument.open(pdfBytes)) {
String text = doc.extractText(0);
}
テキスト抽出
0始まりのインデックスですべてのページをループ処理します。
import fyi.oxide.pdf.PdfDocument;
import java.nio.file.Path;
try (PdfDocument doc = PdfDocument.open(Path.of("book.pdf"))) {
for (int i = 0; i < doc.pageCount(); i++) {
System.out.println("--- Page " + (i + 1) + " ---");
System.out.println(doc.extractText(i));
}
}
単語単位の抽出
PdfPage は構造化された座標情報を提供します。words() は TextWord のリストを返し、各要素にはテキスト、バウンディングボックス、OCR の信頼度が含まれます。
import fyi.oxide.pdf.PdfDocument;
import fyi.oxide.pdf.PdfPage;
import fyi.oxide.pdf.text.TextWord;
import fyi.oxide.pdf.geometry.BBox;
import java.nio.file.Path;
try (PdfDocument doc = PdfDocument.open(Path.of("paper.pdf"))) {
PdfPage page = doc.page(0);
for (TextWord word : page.words()) {
BBox b = word.bbox();
System.out.printf("'%s' at (%.1f, %.1f) conf=%.2f%n",
word.text(), b.x0(), b.y0(), word.confidence());
}
}
PdfPage には lines()、chars()、tables()、images()、annotations() のほか、width()、height()、そして部分領域から抽出する text(BBox region) も用意されています。
Markdown への変換
MarkdownConverter ヘルパー(または doc.toMarkdown(...) の便利メソッド)を使って、単一ページまたはドキュメント全体を Markdown に変換します。
import fyi.oxide.pdf.PdfDocument;
import fyi.oxide.pdf.MarkdownConverter;
import java.nio.file.Files;
import java.nio.file.Path;
try (PdfDocument doc = PdfDocument.open(Path.of("report.pdf"))) {
String md = MarkdownConverter.toMarkdown(doc); // ドキュメント全体
Files.writeString(Path.of("report.md"), md);
String pageMd = doc.toMarkdown(0); // 単一ページ
String pageHtml = doc.toHtml(0); // HTML も可能
}
検索
search() はドキュメント全体を走査し、SearchMatch のリストを返します。各要素にはページインデックス、バウンディングボックス、一致したテキストが含まれます。
import fyi.oxide.pdf.PdfDocument;
import fyi.oxide.pdf.search.SearchMatch;
import fyi.oxide.pdf.geometry.BBox;
import java.nio.file.Path;
try (PdfDocument doc = PdfDocument.open(Path.of("manual.pdf"))) {
for (SearchMatch m : doc.search("configuration")) {
BBox b = m.bbox();
System.out.printf("Page %d: '%s' at (%.0f, %.0f)%n",
m.pageIndex(), m.text(), b.x0(), b.y0());
}
}
PDF の作成
Pdf 型は Markdown、HTML、または画像から PDF を生成します。AutoCloseable ですが Cleaner によるバックストップを持たない ため、必ず明示的に、または try-with-resources でクローズしてください。
import fyi.oxide.pdf.Pdf;
import java.nio.file.Path;
try (Pdf pdf = Pdf.fromMarkdown("# Hello\n\nThis is a PDF.")) {
pdf.saveTo(Path.of("out.pdf"));
}
try (Pdf pdf = Pdf.fromHtml("<h1>Invoice</h1><p>Amount: $42</p>")) {
byte[] bytes = pdf.save(); // ディスクではなくメモリにシリアライズ
}
パスワード保護された PDF
open() にパスワードを渡すか、PdfEncryptedException を捕捉した後に authenticate() を呼び出します。
import fyi.oxide.pdf.PdfDocument;
import java.nio.file.Path;
try (PdfDocument doc = PdfDocument.open(Path.of("confidential.pdf"), "secret")) {
System.out.println(doc.extractText(0));
}
エラー処理
PdfException は RuntimeException を継承する(非チェック例外)型で、型付きのサブクラスと、switch によるディスパッチに使える kind() 列挙を備えています。
import fyi.oxide.pdf.PdfDocument;
import fyi.oxide.pdf.exception.PdfEncryptedException;
import fyi.oxide.pdf.exception.PdfException;
import java.nio.file.Path;
try (PdfDocument doc = PdfDocument.open(Path.of("document.pdf"))) {
String text = doc.extractText(0);
} catch (PdfEncryptedException e) {
System.err.println("Password required");
} catch (PdfException e) {
switch (e.kind()) {
case PARSE -> System.err.println("Malformed PDF");
case IO -> System.err.println("I/O error");
default -> System.err.println("PDF error: " + e.getMessage());
}
}
Kotlin
同じ JAR が Kotlin からそのまま使えます — レコードのアクセサはプロパティとして扱われます。
import fyi.oxide.pdf.PdfDocument
import java.nio.file.Path
PdfDocument.open(Path.of("report.pdf")).use { doc ->
println("Pages: ${doc.pageCount()}")
println(doc.extractText(0))
}
次のステップ
- Python ではじめる – Python から PDF Oxide を使う
- Rust ではじめる – Rust から PDF Oxide を使う
- テキスト抽出 – 抽出オプションとレシピの詳細
- PDF の作成 – 高度な作成、暗号化、メタデータ