Skip to content

PDF Oxide 快速上手(Java)

PDF Oxide 是文本提取最快的 Java PDF 库——平均 0.8 ms,在 3830 个真实场景 PDF 上保持 100% 通过率。同一套 Rust 内核还交付给 Python、Go、JS 和 C#;Java 绑定是一层轻量 JNI 封装,以 JDK 11 LTS 为最低版本,并可从同一个 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)); // zero-based page index
}

你可以从路径字符串、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); // whole document
    Files.writeString(Path.of("report.md"), md);

    String pageMd = doc.toMarkdown(0); // single page
    String pageHtml = doc.toHtml(0);   // or 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(); // serialize to memory instead of disk
}

密码保护的 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 extends 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 中使用——record 访问器会变成属性。

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))
}

后续步骤