Skip to content

Ruby API 参考

PDF Oxide 提供原生 Ruby 绑定(gem pdf_oxide),基于 FFI 构建在 cdylib C ABI 之上。该 gem 内置了预编译的原生库,并在 PdfOxide 命名空间下镜像了 Java 绑定的 9 类结构。

gem install pdf_oxide
require 'pdf_oxide'

关于 Rust API,请参阅 Rust API 参考。关于 Python API,请参阅 Python API 参考。关于类型细节,请参阅 类型与枚举

所有持有句柄的对象(PdfDocumentPdfDocumentEditor)都拥有原生内存,必须被关闭。惯用写法是块(block)形式,它会自动关闭;#close 是幂等的。


PdfOxide(模块)

顶层便捷入口以及进程全局开关。

PdfOxide.open(source, password: nil) { |doc| ... } -> PdfDocument

打开一个 PDF 以供读取。委托给 PdfDocument.open。接受文件路径或原始 PDF 字节;块形式会自动关闭。

PdfOxide.version -> String

返回库的版本字符串(例如 "0.3.69")。

PdfOxide.set_max_ops_per_stream(limit) -> Integer

设置进程全局的内容流操作符上限。负的 limit 会恢复默认值(1,000,000);任何非负值都会成为显式上限。返回先前的上限值。

PdfOxide.set_preserve_unmapped_glyphs(preserve) -> Integer

切换文本提取所使用的进程全局 U+FFFD(未映射字形)保留标志。真值/非零表示保留;假值/0 表示过滤(默认)。返回先前的值(01)。


PdfDocument

PDF 的主要只读入口:提取、搜索、转换、渲染以及页面访问。

doc = PdfOxide::PdfDocument.open('invoice.pdf')

构造器与类方法

PdfOxide::PdfDocument.open(source, password: nil) { |doc| ... } -> PdfDocument

从文件系统路径或原始 PDF 字节打开 PDF(对二进制输入会通过 %PDF- 魔数自动识别)。块形式会自动关闭;非块形式返回该文档。可能抛出 FileNotFoundErrorParseErrorEncryptedError

PdfOxide::PdfDocument.new(source, password: nil) -> PdfDocument

不使用块直接构造。建议优先使用 .open

PdfOxide::PdfDocument.extract_text(source, page: 0) -> String

一次性辅助方法:打开、提取某一页的文本,然后关闭。

文档信息

doc.page_count -> Integer

文档中的页数。

doc.pdf_version -> String

PDF 版本字符串(例如 "1.7"),若不可用则为 "unknown"

doc.encrypted? -> Boolean

PDF 是否带有加密字典。

doc.path -> String

文档打开时所用的绝对路径(对于从字节打开的文档则为 <in-memory>)。

身份验证

doc.authenticate(password) -> Boolean

针对该文档的加密进行身份验证。成功时或对于未加密文档返回 true

文本提取

doc.extract_text(page_index) -> String

从单个从零开始的页面提取纯文本(对于没有文本层的页面返回空字符串)。

doc.extract_structured(page) -> Hash

将某一页提取为结构化表示,返回一个包含 page_indexpage_widthpage_height 以及 regions(每项含 kindtextbboxspanscolumn_index)的 Hash。

doc.extract_text_auto(page_index) -> String

自动路由提取:有原生文本处使用原生文本,在 ocr 特性可用时对扫描区域使用 OCR,并带有优雅的原生回退(绝不会抛出 “OCR unavailable”)。

转换

doc.to_markdown(page_index = nil) -> String

将单页转换为 Markdown,当 page_indexnil 时转换整篇文档。

doc.to_html(page_index = nil) -> String

将单页转换为 HTML,当 page_indexnil 时转换整篇文档。

搜索

doc.search(query, case_sensitive: false, regex: false) -> Array<Hash>

在文档中搜索。每个匹配项为 { page:, text:, bbox: { x:, y:, width:, height: } }。传入 regex: true 可将 query 解释为正则表达式(如果该构建不支持正则搜索,则抛出 UnsupportedFeatureError)。

表单

doc.form_fields -> Array<Hash>

{ name:, value:, type:, page: } Hash 形式返回 AcroForm 字段。当该构建缺少表单提取访问器时返回 []

渲染

doc.render(page_index, dpi: 150) -> String

以指定的 DPI 将单页渲染为 PNG 字节数据(BINARY)。

doc.render_with_layers(page_index, dpi: 150, format: 0,
                       background: [1.0, 1.0, 1.0, 1.0], transparent: false,
                       render_annotations: true, jpeg_quality: 90,
                       excluded_layers: []) -> String

渲染一页,使用完整的 RenderOptions 接口,并支持可选内容组(OCG)图层过滤。format0 = PNG,1 = JPEG;excluded_layers 列出要抑制的 OCG /Name。返回编码后的图像字节(BINARY)。

页面访问

doc.page(index) -> PdfPage

位于 index 处页面的轻量级 PdfPage 视图。

doc.pages -> Array<PdfPage>

文档中的每一页(即时求值)。

自动提取

doc.auto_extractor -> AutoExtractor

为该文档配置的 AutoExtractor(带记忆化缓存)。

生命周期

doc.close -> nil

释放原生句柄。幂等。

doc.open? -> Boolean
doc.closed? -> Boolean

文档是否仍处于打开状态 / 是否已被关闭。


PdfPage

PdfDocument 借用的轻量级单页视图。自身不持有任何原生句柄。通过 PdfDocument#page#pages 构造。

page = doc.page(0)

属性

page.parent -> PdfDocument
page.index -> Integer

所属文档以及从零开始的页面索引。

几何信息

page.width -> Float
page.height -> Float

页面在 PDF 用户空间单位下的宽度和高度。

page.media_box -> Hash
page.crop_box -> Hash

媒体框 / 裁剪框的 { x:, y:, width:, height: }(裁剪框会回退到媒体框)。

page.rotation -> Integer

页面的旋转角度(度)。

文本

page.text -> String

提取该页的文本(等同于 parent.extract_text(index))。

page.to_s -> String
page.inspect -> String

简短的检视标签(#<PdfOxide::PdfPage index=N>)。


Pdf

创建并保存 PDF:Markdown/HTML/文本/图像来源、字节导出,以及书签拆分规划。

pdf = PdfOxide::Pdf.from_markdown("# Title\n\nBody")

工厂方法

PdfOxide::Pdf.from_markdown(markdown) { |pdf| ... } -> Pdf

从 Markdown 构建 PDF。

PdfOxide::Pdf.from_html(html) { |pdf| ... } -> Pdf

从 HTML 构建 PDF(通过 html_css 流水线支持 CSS)。

PdfOxide::Pdf.from_text(text) { |pdf| ... } -> Pdf

从纯文本构建 PDF。

PdfOxide::Pdf.from_images(images) { |pdf| ... } -> Pdf

从 JPEG/PNG 字节块的数组构建 PDF(格式会根据魔数自动识别)。

PdfOxide::Pdf.create_empty { |pdf| ... } -> Pdf

创建一个空白的单页 PDF。

静态辅助方法

PdfOxide::Pdf.version -> String

库的版本。

PdfOxide::Pdf.prefetch_models(languages) -> String

为给定的 BCP-47/ISO 语言标签预取 OCR 模型。返回缓存目录路径(在无 OCR 的构建中为空)。

PdfOxide::Pdf.prefetch_available? -> Boolean

该构建是否支持 OCR 模型供给。

PdfOxide::Pdf.plan_split_by_bookmarks_count(source_pdf, level) -> Integer

统计在 level(1 = 顶层,0 = 全部)处拆分 source_pdf(原始字节)将产生的书签拆分段数,但不生成实际输出。

实例方法

pdf.to_bytes -> String

以 BINARY 编码字节形式返回该 PDF。

pdf.save(path) -> String

将 PDF 写入 path。返回所写入的绝对路径。

pdf.close -> nil
pdf.closed? -> Boolean

释放原生句柄(幂等)/ 是否已被关闭。


DocumentEditor

写入侧编辑器:破坏性涂黑、元数据清除、表单填充以及增量保存。每个涂黑操作都采用失败即关闭(fail closed)策略(非零返回会抛出异常)。

PdfOxide::DocumentEditor.open('source.pdf') do |ed|
  ed.add_redaction(page: 0, rect: [100, 200, 300, 250])
  ed.apply_redactions!
  ed.save_to('redacted.pdf')
end

构造器

PdfOxide::DocumentEditor.open(source) { |ed| ... } -> DocumentEditor

针对磁盘上或内存字节中的 PDF 打开一个编辑器。块形式会自动关闭。

PdfOxide::DocumentEditor.new(source) -> DocumentEditor

不使用块直接构造。

涂黑

ed.add_redaction(page:, rect:, color: [0.0, 0.0, 0.0]) -> self

排入一个涂黑矩形(rect = PDF 用户空间下的 [x1, y1, x2, y2]color = [r, g, b])。在调用 apply_redactions! 之前不会实际应用。

ed.redaction_count(page) -> Integer

为该页排入的涂黑总数。

ed.apply_redactions!(scrub_metadata: false, fill_color: [0.0, 0.0, 0.0]) -> self

破坏性地应用所有已排入的涂黑,可选地清除 /Info、XMP 和 JS。

ed.scrub_metadata -> self

在不进行涂黑区域处理的情况下剥离元数据。

表单

ed.set_form_field(name, value) -> self

通过点分隔的完整名称设置一个 AcroForm 字段。布尔型 value 针对复选框/单选框;否则设置文本值。

保存与生命周期

ed.save_to(path) -> String

保存已编辑的 PDF。返回所写入的绝对路径。

ed.to_bytes -> String

以 BINARY 编码字节形式返回已编辑的 PDF。

ed.close -> nil
ed.closed? -> Boolean

释放原生句柄(幂等)/ 是否已被关闭。


AutoExtractor

带类型化原因的自动提取(文本与 OCR 路由,并带优雅的原生回退)。从 PdfDocument 构造。

ax = PdfOxide::AutoExtractor.new(doc)
result = ax.extract_page(0)
warn "degraded: #{result[:reason]}" unless ax.ok?(result[:reason])

构造器与属性

PdfOxide::AutoExtractor.new(document) -> AutoExtractor

包装一个 PdfDocument 以进行自动提取。

ax.document -> PdfDocument

被包装的文档。

分类

ax.classify_page(page_index) -> Hash

廉价的逐页分类器(不涉及 OCR/栅格化)。返回 { reason:, kind:, confidence:, classification: }

ax.classify_document -> Hash

全文档分类器;返回解码后的 JSON 信封。

提取

ax.extract_text(page_index) -> Hash

通过自动路由器提取某一页的文本;返回 { text:, reason:, kind:, confidence:, classification: }

ax.extract_page(page_index, options: nil) -> Hash

丰富的逐页提取,返回完整的 PageExtraction 信封(文本 + 逐区域 bbox + reason + confidence)合并为一个 Hash。

谓词

ax.ok?(reason) -> Boolean

reason 是否表示一次干净的提取。

ax.ocr_fallback?(reason) -> Boolean

是否触发了 OCR 不可用时的优雅回退路径。

PdfOxide::AutoExtractor.prefetch_available? -> Boolean

该构建是否支持 OCR 供给。

常量

AutoExtractor::REASONS —— 类型化原因符号的冻结数组(:ok:native_text_high_confidence:no_text_layer_present:ocr_requested_but_unavailable 等)。AutoExtractor::PAGE_KINDS —— 页面类型符号(:text_layer:scanned:image_text:mixed:empty)。


MarkdownConverter

PdfDocument 转换为 Markdown 或 HTML 的无状态模块。

PdfOxide::MarkdownConverter.to_markdown(doc, page_index = nil) -> String

将一页(或当 page_indexnil 时的整篇文档)转换为 Markdown。

PdfOxide::MarkdownConverter.to_html(doc, page_index = nil) -> String

将一页(或整篇文档)转换为 HTML。


PdfPolicy

进程全局的加密治理策略,采用一次性设置(set-once)语义。请在任何其他 PDF Oxide 操作之前调用 .set

PdfOxide::PdfPolicy.current -> Symbol

当前进程策略模式(:compat:strict:fips_strict)。

PdfOxide::PdfPolicy.set(mode) -> Symbol

设置进程全局策略模式。如果已设置或该构建不支持,则抛出异常。

PdfOxide::PdfPolicy.compat -> Symbol
PdfOxide::PdfPolicy.strict -> Symbol
PdfOxide::PdfPolicy.fips_strict -> Symbol

预设模式符号:接受所有算法 / 拒绝旧算法 / 仅 FIPS 140-3。

PdfPolicy::MODES —— 模式符号到 cdylib 序数的冻结映射。


PdfSigner

PAdES B-B / B-T / B-LT / B-LTA 数字签名签署器。签名是安全操作:每个非零返回都采用失败即关闭策略。

PdfOxide::PdfSigner.new(certificate_handle) -> PdfSigner

从一个不透明的 PKCS#12/PEM 凭据句柄构造签署器。

signer.sign(pdf, level:, tsa_url: nil, reason: nil, location: nil) -> String

以所请求的 PAdES 级别(:b:t:lt:lta)签署原始 PDF 字节。对于 >= :t 的级别需要 tsa_url。返回 BINARY 编码的已签名 PDF 字节。

PdfOxide::PdfSigner.sign(pdf:, certificate_handle:, level:, tsa_url: nil, reason: nil, location: nil) -> String

静态便捷方法:无需构造签署器实例即可签名。

PdfOxide::PdfSigner.pades_level(signature_handle) -> Integer

现有签名句柄的 PAdES 级别序数。

PdfOxide::PdfSigner.document_has_timestamp?(document_handle) -> Boolean

文档是否带有文档级的 /DocTimeStamp

PdfSigner::LEVELS —— 级别符号到代码的冻结映射。PdfSigner::PadesSignOptions —— 镜像 C PadesSignOptionsC 布局的紧凑 FFI::Struct


PdfValidator

无状态的 PDF/A 和 PDF/UA 合规校验。

PdfOxide::PdfValidator.pdf_a?(doc, level: :a1b) -> Boolean

文档是否在 level:a1b:a1a:a2b:a2a:a2u:a3b:a3a:a3u)下符合 PDF/A。

PdfOxide::PdfValidator.pdf_ua?(doc, level: :ua1) -> Boolean

文档是否在 level:ua1:ua2)下符合 PDF/UA。

PdfOxide::PdfValidator.validate_pdf_a(doc, level: :a1b) -> Hash

简化的 PDF/A 结果:{ compliant:, violations: }

PdfOxide::PdfValidator.validate_pdf_ua(doc, level: :ua1) -> Hash

简化的 PDF/UA 结果:{ compliant:, violations: }

PdfValidator::PDF_A_LEVELSPdfValidator::PDF_UA_LEVELS —— 级别到序数的冻结映射。


错误处理

所有 PDF Oxide 异常都派生自 PdfOxide::Error。原生错误码与下列子类一一对应。

begin
  doc = PdfOxide::PdfDocument.open('file.pdf')
  text = doc.extract_text(0)
rescue PdfOxide::FileNotFoundError
  warn 'file not found'
rescue PdfOxide::ParseError => e
  warn "malformed PDF: #{e.message}"
rescue PdfOxide::Error => e
  warn "PDF error: #{e.message}"
ensure
  doc&.close
end
异常 原因
Error 所有 PDF Oxide 错误的基类
UnsupportedPlatformError 内置 cdylib 不支持当前主机平台
ArgumentError 参数在原生调用前未通过校验
IoError 文件系统 / I/O 故障
FileNotFoundError 文件缺失(IoError 的特化)
ParseError 文件头损坏、xref 损坏、提取失败
StateError 操作顺序错误
InvalidStateError 对已关闭句柄进行操作(StateError 的特化)
EncryptedError 加密 / 密码错误故障
PermissionError 加密 PDF 缺少提取/签名权限
UnsupportedFeatureError 该 cdylib 构建未编译此特性
SignatureError PAdES 签名 / 验证失败
RedactionError 破坏性涂黑失败(失败即关闭)
ComplianceError PDF/A · PDF/UA 校验失败
SearchError 原生文本搜索失败
InternalError 通用的原生侧故障

完整示例

require 'pdf_oxide'

# --- Extraction ---
PdfOxide::PdfDocument.open('input.pdf') do |doc|
  puts "Pages: #{doc.page_count}"
  doc.page_count.times do |i|
    puts "Page #{i + 1}: #{doc.extract_text(i).length} characters"
  end

  # Search
  doc.search('configuration', case_sensitive: false).each do |m|
    puts "Page #{m[:page] + 1}: '#{m[:text]}' at (#{m[:bbox][:x]}, #{m[:bbox][:y]})"
  end

  # Render page 1 to PNG
  File.binwrite('page1.png', doc.render(0, dpi: 150))
end

# --- Creation ---
PdfOxide::Pdf.from_markdown("# Report\n\nGenerated by PDF Oxide.") do |pdf|
  pdf.save('report.pdf')
end

# --- Redaction ---
PdfOxide::DocumentEditor.open('source.pdf') do |ed|
  ed.add_redaction(page: 0, rect: [100, 200, 300, 250])
  ed.apply_redactions!(scrub_metadata: true)
  ed.save_to('redacted.pdf')
end

# --- Validation ---
PdfOxide::PdfDocument.open('archive.pdf') do |doc|
  puts "PDF/A-1b compliant: #{PdfOxide::PdfValidator.pdf_a?(doc, level: :a1b)}"
end

Other Language Bindings

PDF Oxide 为所有主流生态系统提供原生绑定:Rust, Python, Node.js, WASM, C#, Golang, Java, PHP, C++, Swift, Kotlin, Dart, R, Julia, Zig, Scala, Clojure, Objective-C, Elixir

后续步骤