github yfedoseev/pdf_oxide v0.3.27
v0.3.27 | New Language Bindings: JavaScript / TypeScript, Go, and C#

latest releases: v0.3.75, go/v0.3.75, v0.3.74...
3 months ago

Language Bindings

  • Go: migrate from cdylib to staticlib for self-contained binaries (#334)pdf_oxide now produces libpdf_oxide.a alongside the cdylib (new staticlib entry in Cargo.toml's crate-type), and go/pdf_oxide.go links the archive directly via per-platform #cgo ... LDFLAGS with the exact system-library list rustc needs. The resulting Go binary is fully self-contained — no LD_LIBRARY_PATH / DYLD_LIBRARY_PATH / PATH configuration required. Windows x64 is produced via a new x86_64-pc-windows-gnu cross-compile row in the release matrix; Windows ARM64 temporarily stays on dynamic pdf_oxide.dll until aarch64-pc-windows-gnullvm stabilises.
  • Node.js: ship prebuilt native bindings via platform subpackages (#335) — switched to the napi-rs style prebuilt-binary model: the main pdf-oxide package drops the install hook, declares per-platform pdf_oxide-<triple> subpackages as optionalDependencies, and ships only compiled lib/ + README.md. binding.gyp links the libpdf_oxide.a / pdf_oxide.lib staticlib with per-OS system-library lists, so the resulting .node is self-contained. npm install pdf-oxide now 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)PdfOxide on NuGet is now NativeAOT-publish-ready and trim-safe. Target frameworks trimmed to net8.0;net10.0. IsAotCompatible=true and IsTrimmable=true flags enabled. The build-csharp release job gains a Verify NativeAOT publish step that dotnet publish a tiny consumer with PublishAot=true + TreatWarningsAsErrors=true on net10.0. Requested by @Charltsing.
  • OCR FFI bridge for Go, C#, and Node.js — added 4 pub extern "C" fn declarations to src/ffi.rs wrapping src/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 returning ERR_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 gains NewOcrEngine(), 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 dimensions error on PDFs with Indexed color space images (#311)extract_image_from_xobject now resolves Indexed palettes via resolve_indexed_palette and expands indices through expand_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 /CA caption extraction, and Algorithm 2.B termination off-by-one correction.
  • Reading order: ColumnAware fragmented single-column body text (#314) — added is_single_column_region guard, 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_cmp with 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 /Widths array (#328) — added FontInfo::has_explicit_widths() and space_gap correction 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_cache on 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 pipelineupdate-go-native-libs now 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-install uses local path verification — uses go mod edit -replace against the locally-staged checkout instead of go 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 with text, markdown, and html format 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 → LibraryImport migration 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 rendering feature (#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_oxide

Python (PyPI)

pip install pdf_oxide

JavaScript/WASM (npm)

npm install pdf-oxide-wasm

CLI (Homebrew)

brew install yfedoseev/tap/pdf-oxide

CLI (Scoop — Windows)

scoop bucket add pdf-oxide https://github.com/yfedoseev/scoop-pdf-oxide
scoop install pdf-oxide

CLI (Shell installer)

curl -fsSL https://raw.githubusercontent.com/yfedoseev/pdf_oxide/main/install.sh | sh

CLI (cargo-binstall)

cargo binstall pdf_oxide_cli

MCP Server (for AI assistants)

cargo install pdf_oxide_mcp

Pre-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.

Don't miss a new pdf_oxide release

NewReleases is sending notifications on new releases.