v0.3.27 | New Language Bindings: JavaScript / TypeScript, Go, and C#
Language Bindings
- Go: migrate from cdylib to staticlib for self-contained binaries (#334) —
pdf_oxidenow produceslibpdf_oxide.aalongside the cdylib (newstaticlibentry inCargo.toml'scrate-type), andgo/pdf_oxide.golinks the archive directly via per-platform#cgo ... LDFLAGSwith the exact system-library list rustc needs. The resulting Go binary is fully self-contained — noLD_LIBRARY_PATH/DYLD_LIBRARY_PATH/PATHconfiguration required. Windows x64 is produced via a newx86_64-pc-windows-gnucross-compile row in the release matrix; Windows ARM64 temporarily stays on dynamicpdf_oxide.dlluntilaarch64-pc-windows-gnullvmstabilises. - Node.js: ship prebuilt native bindings via platform subpackages (#335) — switched to the napi-rs style prebuilt-binary model: the main
pdf-oxidepackage drops the install hook, declares per-platformpdf_oxide-<triple>subpackages asoptionalDependencies, and ships only compiledlib/+README.md.binding.gyplinks thelibpdf_oxide.a/pdf_oxide.libstaticlib with per-OS system-library lists, so the resulting.nodeis self-contained.npm install pdf-oxidenow works out of the box with no TypeScript, Python, C++ toolchain, or native lib on the consumer's machine. - C#: migrate all 881 P/Invoke declarations from DllImport to LibraryImport for NativeAOT (#333) —
PdfOxideon NuGet is now NativeAOT-publish-ready and trim-safe. Target frameworks trimmed tonet8.0;net10.0.IsAotCompatible=trueandIsTrimmable=trueflags enabled. Thebuild-csharprelease job gains aVerify NativeAOT publishstep thatdotnet publisha tiny consumer withPublishAot=true+TreatWarningsAsErrors=trueon net10.0. Requested by @Charltsing. - OCR FFI bridge for Go, C#, and Node.js — added 4
pub extern "C" fndeclarations tosrc/ffi.rswrappingsrc/ocr::OcrEngine:pdf_ocr_engine_create,pdf_ocr_engine_free,pdf_ocr_page_needs_ocr,pdf_ocr_extract_text. Each has#[cfg(feature = "ocr")]with the real implementation and#[cfg(not(feature = "ocr"))]stub returningERR_UNSUPPORTED. Previously only Python had OCR (via direct pyo3); now Go, C#, and Node.js can also use OCR when built with--features ocr. Go gainsNewOcrEngine(),NeedsOcr(),ExtractTextWithOcr(). - Node.js binding.cc cleanup — deleted 12 hallucinated C++ class methods that referenced nonexistent FFI functions (ML/analysis ×7, XFA parse/free ×2, rendering extras ×3). Wired 6 rendering/annotation/PDF-A functions to their real Rust FFI names using Go's working code as the reference. Fixed macOS framework linking (
xcode_settings.OTHER_LDFLAGS) and MSVC C++20 (/std:c++20).
Bug Fixes
- Image extraction:
Invalid RGB image dimensionserror on PDFs with Indexed color space images (#311) —extract_image_from_xobjectnow resolves Indexed palettes viaresolve_indexed_paletteand expands indices throughexpand_indexed_to_rgb, supporting 1/2/4/8 bpc with RGB/Grayscale/CMYK base color spaces. Reported by @Charltsing. - Encryption: AES-256 (V=5, R=6) PDFs returned empty or garbled text (#313) — three independent fixes: uncompressed-object string decryption, push-button widget
/MK /CAcaption extraction, and Algorithm 2.B termination off-by-one correction. - Reading order:
ColumnAwarefragmented single-column body text (#314) — addedis_single_column_regionguard, fixed vertical-split partition inversion. Verified on RFC 2616, Berkeley theses, EU GDPR. - Tables: product data sheet label/value rows rendered far from their section (#315) — replaced with inline-table-insertion scheme that drains tables at their spatial position.
- Reading order: tabular content interleaved by Y jitter (#316) — added
row_aware_span_cmpwith 3pt Y-band quantisation. CJK rowspan-label columns preserved through spatial table detector (#329). - Text extraction: adjacent Tj/TJ operators concatenated without spaces (#326) — lowered word-separation threshold to match pdfium's heuristic.
- Text extraction: fallback-width inflation on fonts with no
/Widthsarray (#328) — addedFontInfo::has_explicit_widths()andspace_gapcorrection for proportional fonts. - Text extraction: Arabic content in visual order instead of reading order (#330) — added Pass 0 pre-shaped Arabic span reversal.
- Encryption: object cache not invalidated after successful late authenticate() (#323) — drops
object_cacheon the authenticated transition. - Images: Indexed palette expander hardened against DoS and truncation (#324) —
checked_mul+ 256 MiB guard + truncation rejection. - Rendering: slow cold-cache start, dropped ligatures, text missing on subset-CID fonts (#325, #331 R1/R2/R4) — fixed multi-character cluster width accumulation, Arabic/Latin ligature expansion, and system fontdb caching. Reported by @frederikhors.
Release Infrastructure
- Go module tag creation moved to end of pipeline —
update-go-native-libsnow depends on ALL build + verify jobs. The Go tag is created only after the full build matrix is green, and publishes are gated on it. This prevents sum.golang.org from permanently caching a broken tag hash on failed runs. verify-go-installuses local path verification — usesgo mod edit -replaceagainst the locally-staged checkout instead ofgo get @vX.Y.Z, eliminating sum.golang.org contact entirely during CI.- Go tag creation guarded against re-push — skips if tag already exists on remote.
Tooling
scripts/regression_harness.py— new self-contained regression harness. Subcommands:collect/run/diff/groundtruth/show. 60-PDF curated corpus withtext,markdown, andhtmlformat support.
Community Contributors
Thank you to everyone who reported issues or filed detailed reproducers for this release!
- @Charltsing — Reported the Indexed color space image extraction failure (#311) with a reproduction PDF that exposed a long-standing gap in palette handling, and requested the
DllImport → LibraryImportmigration for NativeAOT-ready C# bindings (#333). - @Goldziher — Reported four extraction issues (#313, #314, #315, #316) with clear repro snippets that let us localise the AES-256 string-decryption gap, the Algorithm 2.B termination off-by-one, the single-column XYCut fragmentation, the inline-rendering gap on product data sheets, and the row-aware sort gap for tabular content. Also raised the pdfium-parity bar (#320) that drove the corpus-wide quality audit and the regression harness.
- @frederikhors — Reported the rendering-path bugs on the
renderingfeature (#325): cold-cache slowness, dropped ligatures, missing text on subset-CID fonts, and a font-specific vertical flip. Triage of the report surfaced four distinct signatures (#331 R1-R4); the three that we could reproduce ship in this release.
Installation
Rust (crates.io)
cargo add pdf_oxidePython (PyPI)
pip install pdf_oxideJavaScript/WASM (npm)
npm install pdf-oxide-wasmCLI (Homebrew)
brew install yfedoseev/tap/pdf-oxideCLI (Scoop — Windows)
scoop bucket add pdf-oxide https://github.com/yfedoseev/scoop-pdf-oxide
scoop install pdf-oxideCLI (Shell installer)
curl -fsSL https://raw.githubusercontent.com/yfedoseev/pdf_oxide/main/install.sh | shCLI (cargo-binstall)
cargo binstall pdf_oxide_cliMCP Server (for AI assistants)
cargo install pdf_oxide_mcpPre-built Binaries
Download archives for Linux, macOS, and Windows from the assets below. Each archive includes both pdf-oxide (CLI) and pdf-oxide-mcp (MCP server).
Platform Support
| Platform | Architecture | Archive |
|---|---|---|
| Linux | x86_64 (glibc) | pdf_oxide-linux-x86_64-*.tar.gz |
| Linux | x86_64 (musl) | pdf_oxide-linux-x86_64-musl-*.tar.gz |
| Linux | ARM64 | pdf_oxide-linux-aarch64-*.tar.gz |
| macOS | x86_64 (Intel) | pdf_oxide-macos-x86_64-*.tar.gz |
| macOS | ARM64 (Apple Silicon) | pdf_oxide-macos-aarch64-*.tar.gz |
| Windows | x86_64 | pdf_oxide-windows-x86_64-*.zip |
Changelog
See CHANGELOG.md for full details.