更新日志
PDF Oxide 的所有重要变更都记录在此。
v0.3.38 – 2026-04-22
DocumentBuilder登陆每个绑定;写入路径上的 AES-256;签名验证;多目标 WASM;Go purego 后端
所有绑定上的写入端 API 一致性 (#384)
DocumentBuilder+FluentPageBuilder+EmbeddedFont现在与 Rust 一道在 Python、Node/TypeScript、C#、Go 和 WASM 中提供。通过嵌入字体进行多页构建,全面支持 CJK / 西里尔文 / 希腊文。跨语言关闭 #382。- 每个绑定上的 15 种注释方法:
link_url/link_page/link_named、highlight、underline、strikeout、squiggly、便签、印章(14 种标准 + 自定义)、自由文本、watermark(自定义 / DRAFT / CONFIDENTIAL)。 - 每个绑定上的 5 种 AcroForm 控件类型:
text_field、checkbox、combo_box、radio_group、push_button。 - 每个绑定上的图形基元:
rect、filled_rect、line。 - HTML+CSS 管线 — 在每个绑定中通过
Pdf.from_html_css(...)和from_html_css_with_fonts(...)支持多字体级联。
写入路径上的 AES-256 加密 (#386)
- 每个绑定的
DocumentBuilder上的save_encrypted(path, user_pw, owner_pw)/to_bytes_encrypted(user_pw, owner_pw)。 - Rust 中用于自定义算法 + 权限的
save_with_encryption。
真正的字体子集化 (#385 / FONT-3b)
- CJK 字型现在以子集而非完整字型嵌入。由约 17 MB 的 CJK 字体构建的 5 字符 PDF 通常小于 100 KB。内容流、
/W宽度和ToUnicodeCMap 都被重新映射到子集 GID 空间;extract_text往返保持不变。 - 内部写入器 API 变更:
EmbeddedFont::encode_string/encode_shaped_run返回Vec<u16>,build_embedded_font_objects返回一个供调用方传给ContentStreamBuilder::build_with_remappers的GlyphRemapper。高层 API 没有变化。
数字签名验证 (#208,验证部分)
- 每个绑定中的
Signature.verify()和Signature.verify_detached(pdf_bytes)(以及各绑定的原生等价物)。RFC 5652 §5.4 签名者属性 + §11.2messageDigest检查。 - 基于 SHA-1 / SHA-256 / SHA-384 / SHA-512 的 RSA-PKCS#1 v1.5 返回
Valid/Invalid。RSA-PSS 和 ECDSA 表现为Unknown/UnsupportedFeatureException;调用方仍可读取证书并运行自己的检查。 Certificate— 通过x509-parser进行 DER 检查(subject、issuer、序列号、有效期、is_valid)— 每个绑定。Signature— 枚举 + 检查 +.get_certificate()— 每个绑定。Timestamp— RFC 3161TSTInfo解析(时间、序列号、策略、TSA 名称、哈希算法、消息印记)— 每个绑定。TsaClient— 在tsa-clientCargo 特性后面,带 nonce 和 HTTP Basic 认证的 RFC 3161 HTTP POST — 除 WASM 外的每个绑定。有意未在 WASM 上接通(ureq 与 wasm 不兼容)。DocumentEditor::set_producer/set_creation_date元数据写入器。render_page_region和render_page_fit— 裁剪和适配的渲染表面。- 双三次图像滤波(与 pdf.js #19978 一致)— 带 Multiply 混合叠加的扫描 / 二值页面在缩小时不再压扁其灰度范围。
签名本身(与验证相对)不在此次覆盖范围内;该部分仍由 #208 保持开放。
多目标 WASM 打包 (#392)
pdf-oxide-wasm现在通过package.json的条件导出并排提供三种构建:nodejs/、bundler/(Vite / webpack / Rollup / esbuild / Bun)和web/(浏览器 / Deno / Cloudflare Workers)。- 修复了在浏览器打包器下抛出的
ReferenceError: Can't find variable: __dirname。 - 提供子路径导入(
pdf-oxide-wasm/web、/nodejs、/bundler)以便手动路由。
Go 绑定 — purego 后端 + 缓存目录安装
- 通过 ebitengine/purego 实现的第二个后端在运行时
dlopenlibpdf_oxide.{so,dylib,dll}。CGO_ENABLED=0构建现在可以工作了。 后端选择是自动的 —//go:build cgo→ 完整 CGo API,//go:build !cgo→ purego。 - Purego 覆盖面:
PdfDocument打开(路径 / 字节 / 密码)、页数、版本、文本 / Markdown / HTML / 纯文本提取、字体、注释、页面元素、搜索、页面尺寸、日志,以及用于测试固件的PdfCreator.FromMarkdown。 - 仅 CGo(在
!cgo下为编译时错误):DocumentEditor、DocumentBuilder、条形码、签名、TSA、渲染、OCR、表单变更。 - 安装程序:新的
-shared标志获取 cdylib 而非 staticlib,并打印需导出的CGO_ENABLED=0+PDF_OXIDE_LIB_PATH=…。 - 安装目录已移至
os.UserCacheDir()—~/.cache/pdf_oxide(Linux)、~/Library/Caches/pdf_oxide(macOS)、%LocalAppData%\pdf_oxide(Windows)。与 Go 自身的GOCACHE惯例一致。 - 发布资产现在为每个 Tier-1 平台包含
pdf_oxide-go-ffi-shared-<platform>.tar.gz,与现有的 staticlib 归档并存。
缺陷修复
- #395 – 当页面包含无法解析的签名字段元数据但没有交互式签名控件时,
RenderPage不再抛出SignatureException。由 @gevorgter 报告。
致谢
- @sparkyandrew – #382(通过
DocumentBuilder的 CJK)、#385(子集化器)。 - @arthurlassagne – #392(浏览器构建中断)。
- @gevorgter – #395(
RenderPage签名异常)。
v0.3.37 – 2026-04-20
HTML + CSS → PDF (#248) — 首条可信的纯 Rust 管线
新 API — Pdf::from_html_css
let font = std::fs::read("DejaVuSans.ttf")?;
let pdf = Pdf::from_html_css(
"<h1>Hello</h1><p>World</p>",
"h1 { color: blue; font-size: 24pt }",
font,
)?;
pdf.save("out.pdf")?;
传入 HTML + CSS + 字体字节,得到一份分页的 PDF。纯 Rust,仅 MIT/Apache(无 MPL 传递依赖),extract_text 往返逐字节相等,因此生成的 PDF 可参与现有的测试基础设施。
此次交付的内容
- 字体子系统 — 带
Type 0/CIDFontType2/ Identity-H /ToUnicode发射的 TTF/OTF 嵌入;拉丁文、西里尔文、希腊文、希伯来文、阿拉伯文通过extract_text往返。通过fontdb发现系统字体,通过rustybuzz进行文本整形。 - 手写 CSS 引擎(约 6,500 行代码,零 MPL 依赖)-- 词法分析器、解析器、L3+L4 选择器(
:is/:where/:not/:has)、匹配器、级联、calc()/min()/max()/clamp()、带循环检测的var()、带类型的属性值、at 规则(@media print、带:first/:left/:right/:blank的@page、@font-face、@import、@supports)、计数器、伪元素内容。 - HTML – HTML5 词法分析器、扁平 arena DOM、样式表提取(
<style>、<link rel="stylesheet">、内联style="")、资源提取(<img>+ srcset、<picture>/<source>、<a href>)。 - 布局 – 基于 Taffy 的 block / flex / grid、UAX #14 断行、外边距折叠、多列、表格(auto + fixed)。
- 绘制 – 文本 + 边框、通过 rustybuzz 的 RTL、
<a href>→/Link注释、<img>data-URI →/XObject、::before/::after、page-break-{before,after}: always、opacity、transform: translate*()、<ul>/<ol>列表标记、通过DocumentBuilder::register_embedded_font的嵌入字体 (#382)。
多字体级联
Pdf::from_html_css_with_fonts(html, css, Vec<(family, bytes)>)— 任意元素上的 CSSfont-family都会针对已注册的字体族解析(不区分大小写,带/不带引号,未加引号的多词)。
边角情况修复
- Base-14 粗体文本现在渲染为粗体(针对
Tf /Helvetica-Bold的资源字典键不匹配)。 - TTC 系统字体(Helvetica.ttc、msgothic.ttc)现在通过
fontdb的Source::SharedFile解析。 - 未加引号的多词
font-family现在正确词法化。 - 关闭了
Pdf::from_html_css工厂中的内存泄漏(四处Box::leak被替换为作用域内的局部变量)。 - PNG alpha / 软蒙版(
SMask)现在可以渲染。 - 整形后的文本通过
extract_text往返(encode_shaped_run将字形簇映射回源码点)。 PdfWriter::finish现在按注册顺序嵌入字体(此前为 HashMap 随机顺序)。- 嵌入字体名称冲突通过单调递增的
EFn资源名隔离。 fontdb的 Mutex 不再在字体字节的fs::read期间被持有。
不在范围内
CSS 滤镜、3D 变换、动画、HTML 中的 SVG(每个可用的 Rust SVG crate 都是 MPL)、MathML、hyphens: auto、shape-outside、JavaScript、全矩阵 transform(scale/rotate)、渐变、box-shadow。
许可证审计
cargo deny check licenses 以零 MPL 传递依赖通过。Mozilla 的 CSS 技术栈(cssparser、selectors、html5ever、lightningcss、stylo)全部为 MPL-2.0;v0.3.37 手写了等价实现,以使 pdf_oxide 完全处于 MIT/Apache 之下。
致谢
- @jmriebold – #248(“CSS 支持”)是本次发布整个 HTML+CSS→PDF 管线的根源。
v0.3.36 – 2026-04-19
Markdown 结构提取 — 标记式 PDF 的标题/列表发射、多列阅读顺序、更安全的 RTL 处理
Markdown 结构提取 (#377)
to_markdown() 现在将 /StructTreeRoot 直接接入 Markdown 管线,而不再从字号启发式重新推导标题级别、从字形检测重新推导列表标记:
- 从
/StructTreeRoot发射标题和列表。 附加到每个 span 的新StructRole(Heading(1..6)、ListItem、ListItemLabel、ListItemBody)。Word 标记的文档恢复其完整的标题层级;列表在每次角色转换处带段落断点发射- item。 - 角色在嵌套 MCR 中传播。
H1 → Span → MCR和LI → LBody → Span → MCR模式现在通过InheritedContext { heading_level, list_role }携带正确的语义角色。 - 每个
/StructTreeRoot块边界强制段落断点。OrderedContent.block_id在每次进入/P、/H1..6、/LI、/Lbl、/LBody、/Sect、/Div、/Art、/TR、/TH、/TD、/Note、/Reference、/BibEntry、/Code时递增;紧凑间距的布局不再合并。 - 针对表单标题过度碎片化的同基线门控 — 同基线的 span 重新合并为一个标题。
- 多列栏间空隙检测 — 由
> max(3 × font_size, 30 pt)分隔的同基线 span 被视为跨列。 - 逆向 x 阅读顺序换行检测 — 列优先阅读顺序(第 1 列最后一个 span 在 x=976 → 第 2 列第一个 span 在同基线 x=192)现在断开段落而非连接。
- 针对未标记文档的几何标题 + 列表前缀检测。 粗体 + 5 % 的字号增幅提升为 H4。新的
is_ordered_list_marker识别1./12./a)/iv./A.,同时拒绝图注和年份。
RTL 文本 — 默认安全
- 阿拉伯文上下文字形周围多余的
**bold**标记现在被剥除(整形转换曾使字重检测器误判)。 - Bidi 重排序默认关闭。 早先的草稿曾对每一行 RTL 文本运行
unicode-bidi的视觉→逻辑重排序,这破坏了此前正确的逻辑顺序 PDF(希伯来文名字בנימין被反转了)。重排序辅助函数仍保留在text::bidi::reorder_visual_to_logical,供输入为视觉顺序的调用方使用。
Markdown 输出
- 内联图像的 base64 data URI 上限为 200 KB。 含高分辨率图表的 PDF 此前会将 Markdown 输出膨胀 10–20 倍(一份 1.9 MB 的论文产生了 11.3 MB 的 Markdown)。超出上限的图像发射一个带原始大小的 HTML 注释占位符。基于文件的图像输出(
image_output_dir)不受影响。
实证影响
针对横跨学术、政府、表单、报纸、技术、学位论文、IRS、pdfium、pdfjs、safedocs 和慢速语料子集的 369 个 PDF 回归集,相对 v0.3.35 进行了验证:
- 0 个灾难性回归。
- 相对 pdfium 和 pdftotext 的 Token Jaccard:中位数 1.000,在 106 个固件中有 95 个 ≥0.95。
- 相对 pymupdf4llm 的 Token Jaccard:中位数 0.978,在 106 个固件中有 65 个 ≥0.95。
- 在整个语料中发射的标题约为 pymupdf4llm 的 2 倍。
致谢
- @Goldziher(kreuzberg)-- 提交了 #377,附带一套 727 文档的基准方法论以及 9 个复现用 PDF。其框定(“TF1 在 ±3 % 以内,所以文本内容没问题,问题在结构”)让整个调查变得可处理。
v0.3.35 – 2026-04-19
文本提取中窄字形二连体的保留
文本提取正确性
- 小字号下相邻的窄字形二连体不再被压扁 (#378,PR #379)。
TextExtractor::deduplicate_overlapping_chars和deduplicate_overlapping_spans曾使用硬编码的 2 pt 绝对阈值;对于紧凑字体小字号下的窄字形(l、r、I、i),每字形的步进宽度降至 ≤ 2 pt(Helvetica 的l在 9 pt 时约 2.5 pt),因此相隔整整一个步进的合法相邻二连体落入了去重窗口内,两个字形中的一个被悄无声息地丢弃。可见的损坏包括controller → controler、billed → biled、warranty → warrnty、following → folowing、VIII → VII。阈值现在随每个字形自身的advance_width缩放,为min(advance_width * 0.30, 2.0)。可调参数提升至TextExtractor::DEDUP_OVERLAP_RATIO/DEDUP_OVERLAP_CAP_PT关联常量。
致谢
- @Hugues-DTANKOUO – 以精确的根因分析报告了 #378,并撰写了 PR #379,其中带有按步进缩放的阈值和一套参数化的回归矩阵(4 个窄字形 × 3 种正文字号)。
v0.3.34 – 2026-04-17
所有绑定上惯用的页面 API;结构化表格提取
新特性
- 页面 API (#371) – Python、Node.js、C# 和 Go 现在都暴露一个
PdfPage对象。用for page in doc、for (const p of doc)、foreach (var p in doc.Pages)或doc.Pages()迭代;用doc[i]、doc.page(i)、doc[i]或doc.Page(i)索引。每个页面都暴露惰性的text、markdown()、html()、words、lines、tables、images、paths、annotations、search()等。 - 结构化表格提取 (#289) –
extract_tables()(Python)、ExtractTables()(C#/Go)和extractTables()(Node.js)现在返回带文本及边界框的行和单元格,而不仅仅是 Markdown。在PdfDocument和新的PdfPage上均可用。 - Node.js 一致性 –
extractWords、extractTextLines、extractTables、extractPaths、getEmbeddedImages、ocrExtractText接入了 TypeScript 层(此前仅原生)。 ExtractedTable→Table– Rust 核心重命名;去掉了冗余的Extracted前缀。面向 FFI 的类型已更新。
文本提取质量
- 混合布局页面上的 XY-cut 列检测 (#319) –
is_multi_column_page守卫收紧为每列至少需要 15 个 span;按列排序的 span 不再被extract_text中的行感知排序重新排序。
致谢
- 感谢 @SeanPedersen 提出页面优先 API (#371)。感谢 @pdenapo 请求结构化表格提取 (#289)。
v0.3.33 – 2026-04-16
文本提取、图像正确性和内存安全修复
缺陷修复
- ToUnicode CMap 缺失 (#363) – 当 ToUnicode CMap 中缺少某 CID 时,子集 Type0 字体现在发射 U+FFFD,而不是落到 Identity-H 密文(例如
%B+$%8A//$2*%01*1%6APP)。 - 词内 TJ 字距不再拆分单词 (#365) – 单个单词内 0.10–0.20 em 的字符对字距(
[(diffe) -150 (rent)])不再触发空格插入。 - 西里尔文 UTF-8 乱码已恢复 (#317) – 带仅拉丁文编码和原始 UTF-8 字节序列的字体现在能正确解码。
- FlateDecode 部分恢复拒绝垃圾输出 (#364) – 内容流在解压中途失败的 MS Reporting Services PDF 不再返回 128 字节的伪随机数据。
- Indexed + ICCBased 调色板 (#373) – Indexed 基础数组内未解析的 ICC 流引用不再将
/N默认为 3 而非 CMYK 的 4,修复了对角条纹伪影。由 @Charltsing 报告。 - 基于 Lab 的 Indexed 调色板 → sRGB (#337) – CIE L*a*b* 调色板字节现在转换为 Lab→XYZ→sRGB,而不再被重新解释为原始 RGB。
内存与性能
- 所有内部缓存均有界 (PR #369、#354) – 对象缓存(64 MB)、字体缓存(256–512 项)、XObject span/图像缓存(1024 项)和全局 CMap 缓存(1024 项)现在使用 FIFO 淘汰。
- 修复图表密集 PDF 上路径提取的 OOM (#369) – 添加了 CTM 感知的 XObject 去重,因此同一位置的同一 XObject 被去重,而不同位置的同一 XObject 单独处理。
- Mutex 中毒韧性 –
MutexExt::lock_or_recover()替换了 72 处.lock().unwrap()调用点。
依赖项
- RustCrypto cipher 0.5 生态(PR #352、#295、#291):
aes0.8→0.9、cbc0.1→0.2、sha2/sha1/md-50.10→0.11。
测试套件
- 移除了 13 个失效/陈旧的被忽略测试;修复了 3 个此前被忽略的测试。为上述每个缺陷修复添加了回归测试。套件现为 6,300 通过、0 失败、228 忽略。
致谢
- 感谢 @Charltsing 报告 Indexed + CMYK 图像提取缺陷 (#373)。
- 感谢 @ddxtanx 剖析多页提取期间的无界内存增长 (#354)。
- 感谢 @andrewjradcliffe 贡献 PR #369:有界 FIFO 缓存、CTM 感知的 XObject 去重、
MutexExt中毒恢复 trait、Python 绑定加固。
v0.3.32 – 2026-04-15
针对 Windows-x64 Go FFI tarball 的发布管线修复
发布管线
- 修复使 v0.3.31 发布失败的
x86_64-pc-windows-gnu原生库构建 –scripts/shrink-staticlib.sh曾对每个归档成员运行objcopy --strip-debug,但 MinGW 交叉编译工具链会发射仅含 DWARF 段的分离调试.dwo成员;剥离后该成员没有任何段剩余,objcopy 中止了整个归档。修复:在调用objcopy之前用ar d删除.dwo归档成员。对 Rust、Python、Node、WASM 或 C# 制品没有功能性变更 – 本次发布仅为解锁 Windows-x64 的 Go 安装路径而存在。
v0.3.31 – 2026-04-13
缺陷修复、Go 构建变更、发布基础设施改进
缺陷修复
- Xref 恢复 – 修复了对被误标记的空闲页面对象以及偏差几字节的 xref 偏移项的恢复。
破坏性变更
- Go 原生库 – 原生库不再提交到
go/lib/。使用者必须在每台机器上运行一次go run github.com/yfedoseev/pdf_oxide/go/cmd/install@latest。
发布基础设施
- 将 Rust staticlib 缩小 63%(71 MB 至 26 MB)、剥离 npm
.node插件、从 npm 去除 sourcemap、修复 crate sdist 泄漏、收紧 NuGet snupkg 打包。
v0.3.27 – 2026-04-12
Go staticlib、Node.js 原生绑定、C# NativeAOT、OCR FFI、重大缺陷修复
新特性
- Go staticlib 迁移 – 从 cdylib 切换到 staticlib,以获得自包含的 Go 二进制文件。
- Node.js 原生绑定 – 通过 napi-rs 风格分发的预构建平台子包。
- C# LibraryImport – 为 NativeAOT 兼容性,将 881 个 P/Invoke 声明从 DllImport 迁移到 LibraryImport。
- OCR FFI 桥接 – OCR 支持现在在 Go、C# 和 Node.js 绑定中可用。
- 回归测试框架 – 用于自动化质量测试的 60-PDF 精选语料。
缺陷修复
- Indexed 色彩空间图像、AES-256(V=5、R=6)加密、单列和表格内容的阅读顺序、阿拉伯文文本提取、单词分隔、字体宽度回退、对象缓存失效、渲染改进。
v0.3.24 – 2026-04-09
面向 JavaScript/TypeScript、Go 和 C# 的官方绑定
新特性
- JavaScript/TypeScript 绑定 – 在 npm 上发布,具备完整 API 覆盖。
- Go 绑定 – 具备完整 API 面的原生 Go 包。
- C# 绑定 – 在 NuGet 上发布的 .NET 包。
- C FFI 层 – 270+ 个
extern "C"函数,带共享的pdf_oxide.h头文件。 - 全局日志级别控制 – 可在所有绑定中配置。
v0.3.23 – 2026-04-09
关键稳定性修复
缺陷修复
- 修复了带有旋转 dvips PDF 退化 CTM 的页面上的 SIGABRT。
- 修复了保存时图像/XObject 被剥离的问题。
- 修复了在缺少常见字体的系统上的乱码渲染。
- 修复了表单字段页面索引始终返回 0 的问题。
v0.3.22 – 2026-04-08
线程安全文档、异步 Python、自由线程 Python、单词/行分割调优
新特性
- 线程安全的 PdfDocument – 通过 Mutex 实现
Send + Sync(替换 RefCell)。 - 异步 Python API –
AsyncPdfDocument、AsyncPdf、AsyncOfficeConverter。 - 自由线程 Python – 支持
cp314t(无 GIL 构建)。 - 分割阈值 – 用于调优单词/行检测的
word_gap_threshold、line_gap_threshold、profile。
缺陷修复
- CLI 拆分/合并空白页、对格式错误图像的渲染跳过、结构树循环 SIGSEGV、表格策略门控。
性能
- 缓存结构树和解压后的内容流、O(1) MCID 查找、O(log n) 页面树遍历、惰性页面树填充。
v0.3.21 – 2026-04-04
多架构 Python wheel、日志级别修复
缺陷修复
- 日志级别现在在 Python 中得到完全尊重(宏被转发到 log crate)。
新特性
- 多架构 Python wheel – Linux aarch64、musl x86_64/aarch64、Windows ARM64;将 glibc 要求降至 2_28。
v0.3.20 – 2026-04-04
重大的表格提取重写、文本质量改进、默认静默日志
新特性
- 表格提取引擎重写 – 交叉管线、文本边缘检测、扩展网格、列感知文本检测、点线/虚线重构、混合行检测。
- 文本提取质量 – 相邻值间距、拆分小数合并、粗体 span 合并、HTML 标题层级、标签-值配对、列分组合并。
- 静默日志 – 日志现在在所有绑定中默认静默;Python 日志通过 pyo3-log 流入
logging模块。
缺陷修复
- 加密 PDF 的明确错误消息、ObjStm/XRef 流解密、流解析器尾随换行处理。
v0.3.19 – 2026-04-02
单次调用页面提取、列感知阅读顺序、逐字符边界框
新特性
extract_page_text()– 用于精简页面提取的单次调用 DTO。- 列感知阅读顺序 – 用于多列文档的 XY-Cut 空间分区。
- 逐字符边界框 – 由字体度量推导,用于精确的字符定位。
is_monospace标志 – 在TextSpan和TextChar上可用。Pdf::from_bytes()– 跨所有绑定的新构造函数。- 路径操作 – Python 绑定中的
extract_paths()。
缺陷修复
- 多字节调试日志上的 UTF-8 panic、Markdown 间距、Form XObject
/Matrix、旋转文本矩阵、预扫描 CTM 丢失、去重、Tm 缩放文本丢失、Markdown 单词合并、CLI 合并空白文档。
破坏性变更
- WASM – JSON 字段名现在使用 camelCase。
v0.3.18 – 2026-04-01
渲染引擎大修、新的 Python 和 WASM API、开箱即用的 Python
新特性
- 渲染引擎大修 – 正确的字符间距、嵌入字体支持、标准字体度量、填充与描边、裁剪路径、渐变着色、alpha 透明度、模板图像蒙版、页面旋转、分色色彩空间。
- 新的 Python API –
validate_pdf_a、validate_pdf_ua、validate_pdf_x、extract_pages、delete_page、move_page、flatten_to_images、密码构造函数、merge。 - 新的 WASM API –
validatePdfA、deletePage、extractPages、save、密码构造函数、merge。 - 开箱即用的 Python – 渲染、并行、签名和 Office 转换默认启用。
缺陷修复
- 退化 CTM 中止、FlateDecode 压缩炸弹保护(256 MB 上限)、裁剪栈同步。
v0.3.17 – 2026-03-08
表格检测细化、标记式 PDF 优化
改进
- 细化的表格检测 – 要求 2+ 列,减少误报。
- 优化的标记式 PDF 提取管线。
缺陷修复
- 修复了递归 Form XObject 处理上的
RefCell already borrowedpanic。
v0.3.16 – 2026-03-08
智能混合表格提取、Python 类型存根、pathlib 支持
新特性
- 智能混合表格提取 – 并查集聚类、可视线分析、可视 span/表头。
- 专业 ASCII 表格 – 用于终端输出的多行换行。
- Python 类型存根 – 通过 mypy stubgen 自动生成。
- Python PdfDocument – 接受
pathlib.Path并支持上下文管理器。
缺陷修复
- 嵌套 Form XObject 中的段错误、Python 坐标缩放、ASCII 表格 UTF-8 panic。
v0.3.15 – 2026-03-06
页眉/页脚管理、页面模板、范围化提取
新特性
- 页眉/页脚管理 API – 添加、移除和编辑 PDF 制品(artifact)。
- 页面模板 – 用于页码、日期等的动态占位符。
- 范围化提取 – 尊重
erase_regions以获得过滤后的输出。 PdfDocument.from_bytes()– 新的 Python 构造函数。
缺陷修复
- 多列阅读顺序(XY-Cut)、字体标识冲突、Lines 表格策略误报。
v0.3.14 – 2026-03-03
高层渲染、单词/行提取、几何基元、混合表格
新特性
- 高层渲染 API – Rust、Python 和 WASM 中的
Pdf::render_page。 - 单词和行提取 – 跨所有绑定的
extract_words、extract_text_lines。 - 几何基元提取 –
extract_rects、extract_lines。 - 混合表格检测 – 矢量线提示改善表格边界检测。
- API 协调 – 流畅的
.within(page, rect)模式。 - CLI 命令 – 带
--area过滤的render和paths命令。
缺陷修复
- OCR 特性门控发现、XObject span 缓存污染、V=4 加密滤镜、加密的 CIDToGIDMap。
v0.3.13 – 2026-03-02
CJK 文本提取修复
缺陷修复
- CJK/Type0 字体在
extract_chars中的多字节解码、改进的字符定位精度、字符间距缩放。
v0.3.12 – 2026-03-01
文本提取质量、Markdown 转换、性能
改进
- 文本提取质量 – CID 字体宽度计算、字体变化处的单词边界检测、非标准 CID 映射回退、RTL 文本方向性。
- Markdown 转换 – XY-Cut 递归空间分区、标题检测、列表重构。
性能
- 零拷贝页面树遍历、结构树缓存、BT 操作符提前退出、更大的 I/O 缓冲区、移除 xref 重建阈值。
v0.3.10 – 2026-02-26
并行提取、WASM/JavaScript 支持、批处理、文本质量改进
新特性
-
WASM/JavaScript 支持 – 通过 wasm-bindgen 的 WebAssembly 绑定。完整的文本提取、PDF 创建、编辑、表单字段和搜索可在浏览器和 Node.js 中使用。以
pdf-oxide-wasm在 npm 上发布。 -
并行页面提取 – 新的
parallel特性标志,带基于 rayon 的多线程提取。ParallelExtractor将页面分发到工作线程。全局字体缓存确保字体仅解析一次。 -
批处理 API – 新的
BatchProcessor,用于带进度回调和错误收集的多 PDF 工作流。支持顺序和并行处理。 -
OCR 混合检测 – 新的
PageType枚举(NativeText、ScannedPage、HybridPage),带多启发式检测,用于智能 OCR 回退。 -
完整的 WASM/Python API 一致性 – 跨 WASM 和 Python 绑定的 10 个新方法组:表单字段 get/set、图像字节提取、由图像生成 PDF、表单扁平化、PDF 合并、文件嵌入、页面标签、XMP 元数据。
缺陷修复
- 循环 XObject 段错误 – 修复了图像提取期间循环 Form XObject 引用导致的段错误
- XRef /Prev 链溢出 – 将 XRef
/Prev链解析从递归重写为带循环检测的迭代 - 断裂的连字文本 –
repair_ligatures()后处理器修复来自 LaTeX PDF 的损坏文本 - 文本提取质量 – 注释文本提取、引导点规范化、Priority 3 CMap 支持
- 表格提取 – 合并单元格、多行单元格内容、基于字体的表头检测
- 表单字段持久化 – 增量保存现在正确持久化表单字段值的变更
性能
- 仅图像页面跳过 –
page_cannot_have_text()预检查跳过对无字体页面的解压 - SmallVec 操作符操作数 – 栈分配的操作数消除了逐操作符的堆分配
- 跨文档字体缓存 – 在所有 PdfDocument 实例间共享的进程级 LRU 字体缓存
v0.3.9 – 2026-02-24
20+ 项微优化 – 文本提取速度提升 40%
性能
- O(n^2) 字符串拼接修复 – 预分配的
Vec<&str>在末尾连接,替换了二次方的String::push_str()累加 - 仅图像的内容流解析器 –
extract_images()的新快速路径,跳过文本和图形操作符(快 3-5 倍) - 基于指纹的字体缓存 – 通过对 encoding+widths+flags 哈希来标识字体,而非完整结构体比较
- 流式解析器 – 内容流操作符以流式处理,而非收集到 Vec
- 针对 BT/ET 的快速内联解析器 – 对常见文本操作符进行直接字节匹配
- 字节到字符查找表 – 256 项查找表替换热路径中的 HashMap
- 宽度查找表 – 固定大小数组替换字形宽度的 HashMap
- 缩小 Operator 枚举 – 通过装箱大变体从 112 字节降至 40 字节(缩小 64%)
- zlib-rs 后端 – 通过 zlib-ng 移植使流解压快 15-25%
缺陷修复
- 带嵌入程序的字体编码 – 按 PDF 规范正确解析基础编码
- 辅助 Unicode(U+10000+) – 修复了辅助码点的截断
- StandardEncoding 连字映射 – 通过 Adobe Glyph List 正确映射 fi、fl、ff、ffi、ffl
- 康熙部首规范化 – 完整的 U+2F00-U+2FD5 映射表
- RTL 文本字符顺序 – 阿拉伯文/希伯来文以逻辑阅读顺序提取
- 多列文本分离 – 通过间隙分析改进列检测
特性
extract_all_text()– 用于全页文本提取的新便捷方法- StructElem 的
source_role– 在角色映射前保留原始 PDF 角色名
v0.3.8 – 2026-02-20
仅文本解析器 – 图形密集页面快 10-30 倍
性能
- 仅文本内容流解析器 – 新的
parse_content_stream_text_only()快速路径,使用字节级扫描而非完整 nom 解析,跳过 BT/ET 块外的图形操作符 - 字节级图形扫描器 – 原始索引运算替换基于 nom 的操作数循环,以接近 memcpy 的速度处理
- 跳过颜色操作符 – 将 12 个颜色操作符加入字节级跳过列表
- 延迟 q/cm/Q 发射 – 在确认有文本之前延迟图形状态操作,消除约 75% 的回溯开销
- Arc 包裹的 FontInfo 缓存 – 避免在缓存命中时克隆完整的 FontInfo 结构体
- O(n) 页面映射构建 – 单遍遍历替换递归下降
- XObject 名到引用缓存 – 消除 XObject 密集页面上 O(n^2) 的字典克隆
v0.3.7 – 2026-02-19
文本提取质量:洁净率从 95.7% 提升至 99.6%
已验证 – 3,829-PDF 语料
| 指标 | v0.3.6 | v0.3.7 | 变化 |
|---|---|---|---|
| 洁净率 | 95.7% | 99.6% | 3,829 个 PDF 中的 3,812 个 |
| 脏 PDF | 165 | 17 | -90% |
新增 – 解析器与解码器
- BrotliDecode 流滤镜(PDF 2.0)-- 用于 Brotli 压缩流的新解码器
- Xref trailer 选择 – 存在多个 trailer 时的正确 trailer 选择
- 无头部 PDF 恢复 – 当
%PDF-头部缺失时搜索第一个对象标记
新增 – 字体编码
- CFF 字体编码解析器 – 解析 CFF/OpenType 字体程序以获取字符编码
- Type1 字体编码解析器 – 解析嵌入的 Type 1 字体程序以获取字形映射
- 80K+ CID 到 Unicode 映射 – 扩展了 Adobe-CNS1、Adobe-GB1、Adobe-Japan1、Adobe-Korea1
- Shift-JIS/RKSJ 解码 – 日文 Shift-JIS 编码的 CMap 流支持
- Identity-H cmap 传播 – 从 CIDFont 后代传播 TrueType cmap 表
修复 – 文本提取管线
- Tf 缓冲刷新 – 在字体切换时刷新待处理文本以防止文本丢失
- 自适应空格阈值 – 用基于 bbox 的间距替换固定的 0.25em 阈值
- Span 去重 – 对为粗体/阴影效果而渲染的重叠 span 去重
- 字符去重 – 移除同一行内 2pt 以内的重复字符
- 移除 BT 操作符检查 – 修复了跳过有效文本块的错误验证
- ByteMode 解码 – 正确的 1 字节、2 字节和可变宽度字符码解码
- 注释文本提取 – 从 Widget、FreeText 和外观流提取文本
v0.3.6 – 2026-02-16
快 10 倍 – 消除两个 O(n) 瓶颈
性能
-
批量页面树缓存 – 在首次访问页面时,整个页面树被遍历一次,所有页面都被缓存。此前
get_page()为每个未缓存页面从根遍历,导致每页 O(n)、顺序访问总计 O(n^2)。现在在单次 O(n) 遍历后每页 O(1)。一个 10,000 页的 veraPDF 测试文件从 55,667ms 降至 332ms(快 168 倍)。 -
对象扫描偏移缓存 – 当对象在 xref 表中缺失时,
scan_for_object()此前为每个缺失对象读取整个 PDF 文件。带有数百个不在 xref 中的结构树元素的标记式 PDF 会触发数百次整文件读取。现在文件被扫描一次,所有对象偏移都被缓存。一个 10 页的标记式 PDF 从约 10s 降至 68ms(快 146 倍)。一个带 571 个字体的 154 页学术 PDF 从约 18s 降至 405ms(快 44 倍)。 -
单遍文本提取 –
extract_spans()不再运行两遍(先分类文档类型,再提取)。分类遍被完全消除;自适应的字体感知阈值现在在单遍中产生相等或更好的结果。 -
内容流 Vec 预分配 –
parse_content_stream()根据流大小预分配操作符 Vec 容量,减少大型内容流的重新分配。
已验证 – 3,830-PDF 语料(v0.3.5 至 v0.3.6)
| 指标 | v0.3.5 | v0.3.6 | 变化 |
|---|---|---|---|
| 通过率 | 99.8% | 99.8% | 3,830 个有效 PDF 中的 3,823 个 |
| 慢(>5s) | 2 | 0 | 已消除 |
| 平均 | 23.3ms | 2.1ms | -91% |
| p50 | 0.6ms | 0.6ms | – |
| p90 | 3.0ms | 2.6ms | -13% |
| p99 | 33.2ms | 18.0ms | -46% |
| 最大 | 68,722ms | 625ms | -99% |
| 合计(全部 PDF) | 89.1s | 8.0s | -91% |
文本输出在 11 个 PDF(862 KB 提取文本)上验证为逐字节相同。4 个 PDF 因自适应间距而显示出提取质量的提升。
v0.3.5 – 2026-02-15
性能、3,830-PDF 稳定性和错误恢复
性能
- 跨页面字体缓存 – 以 ObjectRef 为键的文档级字体缓存避免在每页重新解析共享字体
- 页面对象缓存 –
get_page()缓存已解析的页面对象,消除多页提取的重复页面树遍历 - 结构树缓存 – 结构树结果在首次访问后被缓存,避免在每次
extract_text()调用时的冗余解析 - BT 操作符提前退出 – 文本提取对不含 BT(Begin Text)操作符的仅图像页面跳过完整管线
- 大文件的更大 I/O 缓冲区 – 对超过 100 MB 的文件,BufReader 容量从 8 KB 增至 256 KB
- 移除 Xref 重建阈值 – 消除了在对象很少的有效组合 PDF 上触发整文件重建的启发式
已验证 – 3,830-PDF 语料
- 在横跨 veraPDF(2,907)、Mozilla pdf.js(897)、SafeDocs(26)的 3,830 个 PDF 上 100% 通过率
- 零超时、零 panic
- p50 = 0.6ms、p90 = 3.0ms、p99 = 33ms
新增 – 加密
- 所有者密码认证 – R<=4 用算法 7,R>=5 用算法 12
- 带 SASLprep 的 R>=5 用户密码验证 – 使用 SHA-256 的完整 AES-256 密码验证
- 公开密码认证 API –
Pdf::authenticate(password)和PdfDocument::authenticate(password)
新增 – PDF/A 合规验证
- XMP 元数据验证 – 检查
pdfaid:part和pdfaid:conformance项 - 色彩空间验证 – 扫描页面内容流以查找无输出意图的设备相关颜色操作符
- AFRelationship 验证 – PDF/A-3 嵌入文件规范验证
新增 – PDF/X 合规验证
- XMP PDF/X 标识 – 验证
pdfxid:GTS_PDFXVersion - 页面框关系验证 – TrimBox 在 BleedBox 内,BleedBox 在 MediaBox 内
- ExtGState 透明度检测 – SMask、CA/ca、BM 检查
- 设备相关颜色检测 – 标记不受支持的色彩空间
- ICC 配置文件验证 – 验证 ICCBased 配置文件流
新增 – 渲染
- 符合规范的裁剪 – 裁剪状态作用域限定于 q/Q 保存/恢复
- 字形步进宽度计算 – 按 PDF 规范 9.4.4 节
- Form XObject 渲染 – 解析 /Matrix 变换,使用表单的 /Resources
修复 – 错误恢复(28+ 个真实世界 PDF)
- 缺失对象按 PDF 规范 7.3.10 节解析为 Null
- 对不寻常版本字符串的宽容头部版本解析
- 非标准加密算法匹配(V=1、R=3 组合)
- 非字典的 Resources 被视为空而非报错
- 优雅地跳过页面树中的 Null 节点
- 损坏的内容流返回空内容而非错误
- 通过 /Resources+/Parent 启发式的增强页面树扫描
修复 – DoS 防护
- 页数针对 PDF 规范附录 C.2 上限(8,388,607)进行验证
修复 – 图像提取
- 通过 Do 操作符的内容流图像提取
- 带循环检测的嵌套 Form XObject 图像
- 内联图像(BI…ID…EI 序列)
- 用于图像定位的 CTM 变换
- ColorSpace 间接引用解析
修复 – 解析器健壮性
- 多行对象头部(Google 生成 PDF 使用的
1 0\nobj格式) - 头部搜索从 1024 扩展到 8192 字节
- 对格式错误头部的宽容版本解析
修复 – 页面访问健壮性
- 无 /Contents 的页面返回空内容
- 循环页面树检测防止栈溢出
- 优雅处理 Null 流引用
- 无 /Type 项的页面通过 /MediaBox 或 /Contents 键找到
修复 – 加密健壮性
- 用过小密钥进行 AES 解密返回错误而非 panic
- 针对格式错误项加固 Xref 流解析
- 在解析前解析间接的 /Encrypt 引用
修复 – 内容流处理
- 针对裸字典的 Dictionary-as-Stream 回退
- 缩写滤镜名(AHx、A85、LZW、Fl、RL、CCF、DCT)
- 内容流操作符上限(默认 1,000,000)
修复 – 代码质量
- 结构树间接对象引用在解析时解析
- Lexer 的 R/RG 词元消歧
- 流空白修剪不再从二进制数据剥除 NUL 字节或空格
测试
- 8 个此前被忽略的测试被取消忽略并修复
移除
- 空的
PdfImage存根(提取使用ImageInfo) - 被注释掉的
DocumentType::detect()测试块
v0.3.4 – 2026-02-12
解析健壮性、字符提取和 XObject 路径
破坏性变更
parse_header()签名从(u8, u8)改为(u8, u8, u64)以包含字节偏移
修复 – PDF 解析健壮性(Issue #41)
- 带二进制前缀或 BOM 头部的 PDF 现在能成功打开
- 头部搜索在前 1024 字节中扫描
%PDF-标记 - 支持 UTF-8 BOM、电子邮件头部和其他前导二进制数据
- 宽容模式处理真实世界的格式错误 PDF;严格模式用于合规测试
新增 – 字符级文本提取(Issue #39)
extract_chars()返回带逐字符定位的Vec<TextChar>- 包含变换矩阵、旋转角度、步进宽度
- 按阅读顺序排序,带重叠字符去重
- 对仅字符的用例比 span 提取快 30-50%
- 在 Rust 和 Python API 中均暴露
新增 – XObject 路径提取(Issue #40)
extract_paths()通过 Do 操作符递归处理 Form XObject- 通过 /Matrix 正确应用坐标变换
- 图形状态被正确隔离(保存/恢复)
- 重复 XObject 检测防止无限循环
- 支持嵌套 XObject
变更
- 将 nom 解析器库从 7.1 升级到 8.0
v0.3.3 – 2026-02-11
CJK 支持、结构树增强和合规基础
包含 v0.2.5 和 v0.2.6 的所有变更,作为一次合并发布。
亮点
- TagSuspect/MarkInfo 支持 – 从文档目录解析 MarkInfo 字典
- 用于 CJK 文本的 Word Break /WB 结构元素
- 针对 Adobe-GB1(简体中文)、Adobe-Japan1(日文)、Adobe-CNS1(繁体中文)、Adobe-Korea1(韩文)的预定义 CMap 支持
- 缩写展开 /E 支持
- 用于 CIDFont 字形宽度的 Type 0 /W 数组解析
- 软连字符(U+00AD)处理修复
- 带子类型支持的增强制品过滤
- HTML 和 Markdown 输出中的图像嵌入(base64 data URI)
- 带
embed_images=false和image_output_dir的图像文件导出 PdfImage::to_base64_data_uri()和to_png_bytes()方法
v0.3.2 – 2026-02-01
编辑、加密和文档安全
新增 – PDF 编辑
- 用于修改现有 PDF 的
DocumentEditor - 完整的注释支持(文本标记、形状、印章、墨迹、文件附件、密文涂改)
- 交互式表单字段创建(文本、复选框、单选、下拉、列表、按钮)
- 表单扁平化
- 链接注释(URL、内部页面导航)
- 大纲/书签构建器
- PDF 图层(可选内容组)
新增 – 加密
- 写入时加密(AES-256、AES-128、RC4-128、RC4-40)
- 权限控制(打印、复制、修改、注释)
- 带
EncryptionAlgorithm和Permissions的EncryptionConfig构建器 - 数字签名基础
v0.3.1 – 2026-01-14
表单字段、多媒体、创建工具和搜索
新增 – PDF 创建
Pdf::from_markdown()、Pdf::from_html()、Pdf::from_text()、Pdf::from_image()- 用于元数据和布局配置的
PdfBuilder流畅模式 - 用于程序化 PDF 生成的
DocumentBuilder - 用
TableRenderer进行表格渲染 - 图形 API:颜色、渐变、图案、混合模式、透明度
- 带页眉、页脚、页码、水印的页面模板
- 条形码生成(QR、Code128、EAN-13、UPC-A、Code39、ITF)
新增 – 搜索
- 带正则、区分/不区分大小写、整词、页面范围的文本搜索
SearchOptions和SearchResult类型- 带页面/坐标的位置追踪
新增 – 表单字段覆盖(95%)
- 层级字段创建(带点分名称的父/子结构)
- 字段属性修改(只读、必填、矩形、工具提示、最大长度、对齐、默认值)
- 用于表单数据交换的 FDF/XFDF 导出
新增 – 多媒体注释
- MovieAnnotation、SoundAnnotation、ScreenAnnotation、RichMediaAnnotation
- 带 U3D 和 PRC 格式支持的 ThreeDAnnotation
新增 – XFA 表单支持
- XfaExtractor、XfaParser、XfaConverter(XFA 到 AcroForm 转换)
变更 – Python 绑定
- 通过 abi3-py38 真正支持 Python 3.8-3.14
- 现代化工具:uv、pdm、ruff 集成
v0.3.0 – 2026-01-10
提取基础 – 统一 API 与核心能力
新增 – 统一 Pdf API
- 用于读取现有 PDF 的
Pdf::open() - 通过
pdf.page(0)的类 DOM 页面导航 - 用于高级用例的
PdfDocument低层句柄
新增 – 文本提取
extract_text()– 全页纯文本extract_spans()– 带字体元数据的样式化文本段- 用于标记式 PDF 的基于结构树的阅读顺序
- 用于未标记 PDF 的智能断行和空格检测
新增 – 图像提取
extract_images()– 从页面提取所有图像- 格式检测(JPEG、PNG、TIFF、JBIG2、CCITT)
- 色彩空间处理(DeviceRGB、DeviceCMYK、DeviceGray、ICCBased)
新增 – 元数据提取
- 文档信息字典(标题、作者、主题、关键词)
- XMP 元数据读/写
- 页面信息(尺寸、旋转、media/crop/trim 框)
新增 – 表单提取
- 用于 AcroForm 字段枚举的
extract_form_fields() - 文本、按钮、选择和签名字段类型
新增 – 转换
to_markdown()– 页面级 Markdown 转换to_html()– 页面级 HTML 转换to_plain_text()– 可配置的纯文本输出
新增 – 合规
- PDF/A 验证(ISO 19005,级别 1a 至 3b)
- PDF/X 验证(ISO 15930,级别 X-1a 至 X-6p)
- PDF/UA 验证(ISO 14289,级别 UA-1 和 UA-2)
新增 – 渲染(需要 rendering 特性)
- 通过 tiny-skia 将页面渲染为 PNG/JPEG
- 可配置的 DPI 和缩放
新增 – Python 绑定
- 带完整提取 API 的
PdfDocument类 - 带创建和高层 API 的
Pdf类 - 基于 PyO3,以
pdf_oxide发布到 PyPI
v0.2.4 – 2026-01-09
- 用于文本定位的 CTM 变换修复
- 结构树
/Alt和/Pg解析 - 用于公式图像的 FormulaRenderer
v0.2.3 – 2026-01-07
- 按 PDF 规范的 BT/ET 矩阵重置
- Markdown 转换器中的几何间距检测
- 用于连字和断字的
apply_intelligent_text_processing()
v0.2.2 – 2025-12-15
- 用于可发现性的关键词优化
v0.2.1 – 2025-12-15
- 加密流解码改进
v0.1.4 – 2025-12-12
- 加密流解码修复
v0.1.0 – 2025-11-06
- 首次发布
- 带符合规范的 Unicode 映射的 PDF 文本提取
- 智能阅读顺序检测
- 通过 PyO3 的 Python 绑定
- 加密 PDF 支持
- 表单字段提取
- 图像提取