Skip to content

v0.17.0

Choose a tag to compare

@github-actions github-actions released this 12 May 04:17
b9949ee

0.17.0 (2026-05-04)

Features

  • add BZZ encoder with ZP arithmetic coding (582432f)
  • add fit_to_width/height/box to RenderOptions (#33) (b371a93)
  • add NAVM bookmark encoder and ANTa/ANTz annotation encoder (#133) (#136) (9e6bf66)
  • api: bundled DJVM mutation + set_bookmarks (PR3 of #222) (#268) (6672a93)
  • api: DjVuDocumentMut::from_bytes — chunk-replacement primitive (PR1 of #222) (#263) (b6279ae)
  • api: high-level setters for DjVuDocumentMut (PR2 of #222) (#267) (eec0815)
  • api: raw_chunk / all_chunks / chunk_ids on DjVuPage and DjVuDocument (Issue #43) (#54) (3135627)
  • async: add native lazy page loader (735a226)
  • async: add wasm lazy reader entrypoint (77fc6ff)
  • async: async render API via tokio::task::spawn_blocking (Issue #51) (#61) (452636f)
  • async: load_document_async — buffered AsyncRead constructor (#196 Phase 1) (#231) (2d85e65)
  • async: page_byte_range API + streaming async loader (#196 Phase 2) (#237) (a365abb)
  • async: progressive stream render API (Issue #81) (#112) (eaff91d)
  • async: resolve lazy shared dictionaries (30d8ac9)
  • bench: add render_scaled and pdf_export benchmarks + BENCHMARKS.md (Issue #52) (#62) (a8523c7)
  • ci: add ocr-tesseract integration test + CI job (#178) (220671d)
  • ci: continuous benchmark tracking — PR regression detection (Issue #88) (#109) (0dfade5)
  • cli: implement djvu info/render/text — 24/24 tests green (eb2e9d6)
  • cli: multi-page djvu encode from a directory of PNGs (#223 follow-up) (#245) (b8858bb)
  • cos-djvu: benchmark suite, corpus infrastructure, BENCHMARKS.md (closes #282) (#332) (50b6933)
  • cos-djvu: phase 1 — IFF parser, typed errors, MIT skeleton (closes #267) (#277) (1943f3f)
  • cos-djvu: phase 2a — ZP arithmetic coder + BZZ decompressor (closes #268) (#279) (4983056)
  • cos-djvu: phase-5 rendering pipeline — compositing, gamma, scaling, AA (closes #273) (7f5e161)
  • cos-djvu: phase-6 quality — fuzz targets, benchmarks, no_std, full docs (closes #274) (#324) (67fab7f)
  • cos-djvu: text layer + annotations extraction (closes #272) (#316) (5beeba9)
  • djvm: add merge and split commands for DjVu documents (#126) (37eefd8), closes #76
  • djvu render --format pdf|cbz, roadmap v0.1 finalised (7d823f6)
  • DjVu to PDF converter with text, bookmarks, and hyperlinks (#2-#6) (#29) (a6f0a74)
  • djvu-enc: high-level PageEncoder for bilevel Lossless (#218) (#243) (afefcef)
  • djvu-enc: minimal layered Quality (segment → Sjbz + BG44) (#246) (2febd04)
  • document model — DjVuDocument, Page, DIRM, NAVM (closes #271) (#283) (e36fd41)
  • epub: DPI-aware rendering, language tag, hyperlinks, cover image (191e386)
  • epub: EPUB 3 export — page images, text overlay, navigation (Issue #74) (9a6d155)
  • epub: opt-in reflowable text section per page (#228) (#240) (8207fb9)
  • ffi: add C FFI bindings via extern "C" functions (#127) (2226bdf), closes #72
  • fgbz-enc: FGbz foreground palette encoder (#217) (#241) (e43bc9f)
  • fuzz: add render to fuzz_full, add CI fuzz workflow (60 s/target) (7e3e4eb)
  • hOCR and ALTO XML export for text layer (Issue #75) (#98) (263cf14)
  • implement ImageDecoder trait for image-rs integration (Issue #80) (#97) (d7e4a64)
  • import cos-djvu history, remove GPL legacy code (0f33110)
  • indirect DJVM — create_indirect() and parse_from_dir() (#135) (#137) (d7fbf74)
  • IW44 wavelet decoder with planar YCbCr (closes #270) (#281) (f799e70)
  • IW44 wavelet encoder — BG44/FG44 chunk encoding (issue #131) (#139) (10adc4f)
  • JB2 bilevel decoder (closes #269) (#280) (e2a6898)
  • JB2 bilevel image encoder — Sjbz chunk encoding (issue #132) (#140) (cf280ba)
  • jb2-enc: expose tunable shared-Djbz clustering + corpus harness (#194 Phase 2) (#219) (9aafe42)
  • jb2-enc: multi-page shared Djbz dictionary in DJVM bundle, Phase 1 (#194) (#216) (507b061)
  • jb2-enc: symbol-dictionary encoder Phases 1-3 (#188) (#213) (8a2ed15)
  • jb2: DJVI shared dictionary support via INCL chunks (Issue #45) (#56) (86a63cb)
  • mask and foreground/background layer extraction API (#36) (d4c6527)
  • mask: wire Smmr (G4/MMR) decoder into both render pipelines (07272b3)
  • metadata: METa/METz document metadata parsing (Issue #44) (#55) (eb4515b)
  • mmap: add memory-mapped I/O via MmapDocument (387a2ea), closes #70
  • ocr: pluggable OCR backend trait with Tesseract, ONNX, and Candle backends (#125) (bf26603), closes #77
  • pdf: DCTDecode background encoding — smaller PDF output (Issue #49) (#59) (de90a9f)
  • pdf: parallel page rendering with rayon (#148) (ae79a7c)
  • progressive DjVu rendering, multi-book cache, cos-diagnostics crate (32432d8)
  • python: add Python bindings via PyO3 (#128) (e250fff), closes #71
  • render: add rayon-based parallel page rendering (3dc06f9), closes #69
  • render: BGjp/FGjp JPEG background/foreground decoder (Issue #47) (#57) (b65bd81)
  • render: grayscale output mode — GrayPixmap + render_gray8 (c13ebb7)
  • render: grayscale output mode — GrayPixmap + render_gray8 (Issue #15) (75d7b37)
  • render: Lanczos-3 separable resampling (Issue #50) (#60) (56817d1)
  • render: permissive render mode — skip corrupted chunks (dc5734a)
  • render: permissive render mode — skip corrupted chunks (Issue #19) (df5a8d7)
  • render: public render_streaming API (Phase 2 of #225) (#260) (b92fac7)
  • render: zero-copy region render — render_region API (Issue #86) (#111) (b2aa2a8)
  • segment + cli: FG/BG segmentation v1 + djvu encode subcommand (#220, #223) (#244) (4945b06)
  • serde support for metadata, annotations, bookmarks, and text zones (Issue #82) (#96) (e872ecd)
  • smmr-enc: public Smmr (G4/MMR) encoder API (#221) (#242) (009c706)
  • smmr: add G4/MMR bilevel image decoder (issue #134) (#138) (8bd6e41)
  • text: add reflowable_text() for paragraph reading-order extraction (#228) (#239) (221a49a)
  • text: TextLayer::transform — rotate + scale zone rects for rendered pages (Issue #46) (#53) (c4a514e)
  • tiff: embed DPI resolution tags in exported TIFF files (87efb14)
  • tiff: TIFF export — multi-page color and bilevel modes (Issue #48) (#58) (dc90cc0)
  • transfer from cos-djvu, remove legacy GPL code, add PD corpus, benchmarks (33fd496)
  • ui: table of contents navigation panel (closes #60) (#298) (3fb0b2a)
  • user-controllable rotation in RenderOptions (#35) (e0f79a8)
  • wasm: add WasmPage::text_zones_json() — text selection overlay API (e513bbf), closes #119
  • wasm: add WasmPage::text() — expose page text layer to JS (35a776d)
  • wasm: progressive IW44 render API (#150) (35d3a30)
  • wasm: WebAssembly bindings via wasm-bindgen (Issue #73) (#118) (4300939)

Bug Fixes

  • add missing chunk_data binding in iw44_new doctest (d1a210b)
  • annotation: add MAX_SEXPR_DEPTH=64 guard to prevent stack overflow on deeply nested S-expressions (#200) (2f03789)
  • apply gamma correction in all legacy render paths (#9) (#22) (dfba614)
  • apply page rotation from INFO chunk in render_pixmap and render_coarse (#10) (#24) (adec5ee)
  • ci: enable cli feature for nextest to build djvu binary (576f12f)
  • ci: exclude djvu-py from nextest, fix audit advisories (788b0d3)
  • ci: exclude fuzz/ from workspace to fix cargo-fuzz builds (330ff0a)
  • ci: IJG license allowlist, no_std BTreeMap, clippy errors (6a2a391)
  • ci: install libleptonica-dev + libtesseract-dev for ocr-tesseract job (0410f70)
  • ci: split test into test-stable + test-beta jobs (matrix.rust not allowed in job if) (0d60c76)
  • ci: use core::mem::take in no_std context; fix clippy redundant-Some in ocr_export test (#101) (cc1cdf1)
  • clippy errors and fmt — let-chain, ref on let, line wrapping (b4ba2f8)
  • clippy: use contains() instead of iter().any() in tiff_export (f9b4c2b)
  • docs: resolve all remaining broken intra-doc links (0 warnings) (4ac8bb1)
  • docs: resolve broken intra-doc links in djvu_document (8dbfda0)
  • eliminate memory leaks and add OOM protection (25f041d)
  • exclude .cargo/config.toml from published package (fixes docs.rs build) (b9dd0da)
  • FGbz multi-color foreground palette — use per-glyph blit index (#12) (#26) (7897164)
  • fuzz: add [workspace] to fuzz/Cargo.toml to fix cargo-fuzz build (be7a5a8)
  • fuzz: revert to cargo install cargo-fuzz, add explicit binary cache (84e6eef)
  • fuzz: use correct public module djvu_rs::jb2 in fuzz_jb2 target (9133de6)
  • hard-rule: eliminate last 5 .expect()/.unwrap() in production code (Issue #443) (#444) (e4247ea)
  • iff: preserve FORM length parity for byte-identical mutation (PR4 of #222) (#269) (df1e95e)
  • iw44: correct vext lane in prelim_flags_band0_neon horizontal-OR (#266) (b390681)
  • jb2_encode: return empty Vec for zero-dimension bitmaps; unreachable dead branch (#142) (#143) (091b657)
  • jb2-enc: cap cluster_shared_symbols pixel budget at decoder limit (#270) (#271) (78e5c79)
  • jb2-enc: tile direct encoder to ≤1MP records (#198) (#214) (24ac60f)
  • jb2,iw44: cap comment bytes and IW44 pixel limit to prevent fuzz timeouts (49c7b1b)
  • jb2,iw44: prevent DoS via refinement bitmaps and uncapped total pixel budget (3e72cf6)
  • jb2: add blit-pixel budget to prevent type-7 dict-copy DoS (1c03505)
  • jb2: cap decode loop at 1 M records to prevent infinite spin on exhausted ZP input (0b84f2d)
  • jb2: correct regression test comment for fuzz2 fix (ee380ae)
  • jb2: guard blit against negative symbol dimensions (49a3792)
  • jb2: guard blit fast path against i32 overflow and data buffer overread (be72d29)
  • jb2: limit symbol bitmap size to 4 MP to prevent DoS via crafted input (943f25e)
  • jb2: prevent infinite loop in decode_num on corrupt streams (d7bee1e), closes #122
  • jb2: reduce MAX_RECORDS and MAX_SYMBOL_PIXELS to prevent fuzz timeouts (3292193)
  • ocr: resolve all clippy errors in ocr_neural, ocr_onnx, ocr_tesseract (65a0cee)
  • pdf: Unicode-aware glyph width for invisible text layer (2398c38)
  • remove deprecated [[licenses.deny]] syntax from deny.toml (cargo-deny v2) (7971e44)
  • render: add #[allow(unsafe_code)] + unsafe blocks for Rust 2024 SIMD (#169) (179d171)
  • render: correct gamma LUT formula to match DjVuLibre (#161) (cd3228d)
  • render: resolve unsafe_code / unsafe_op_in_unsafe_fn CI conflicts (889f28f)
  • render: restore bilevel composite fast path, recover 2× regression from #165 (46b6931)
  • render: scale page-space coords into FG44 + BG plane space (#199) (#248) (e2c07df)
  • render: use core::arch instead of std::arch for no_std compatibility (122b989)
  • replace all internal cos-djvu/cos_djvu references with djvu-rs/djvu_rs (03fb17a)
  • resolve issues #164 #169 #170 #174 #176 #177 (774cbdb)
  • smmr: replace manual div_ceil with .div_ceil() per clippy (a8d24ca)
  • update MSRV to 1.88 (let-chains stabilized in 1.88) (8d5b94f)
  • update tesseract API and optimize JB2 inner loop (f64d884)
  • vendor djvu-rs into crates/cos-djvu and fix production panics (5f6d7fe), closes #4
  • wasm CI job, open_dir API, DPI scaling in OCR export, jb2_new cleanup (6cbe038)
  • wasm: correct render() pixel layout and Uint8ClampedArray allocation (1a967d2)
  • zp: widen a/c/fence fields from u16 to u32 to match jb2 inline decoder (fb0db12)

Performance Improvements

  • allow 1.5× upscale in IW44 subsample selection for faster downscaled renders (8f0baa2)
  • area-averaging downscale for better quality when rendering at reduced size (#13) (#28) (b822ded)
  • bitmap: packed bitwise dilation with ping-pong buffers (2887689)
  • bitmap: packed bitwise dilation with ping-pong buffers (Issue #17) (0814f55)
  • bzz: inline ZP state locals in MTF decode hot loop (bad5b21)
  • bzz: parallel inverse-BWT via rayon (Issue #89) (#110) (eb5bab0)
  • ci: single nextest pass on main avoids sequential overhead (f17d901)
  • deps: split ocr-neural into lightweight stub + ocr-neural-candle (#175) (3a930b2)
  • downsampled mask pyramid for composite — 8 ms vs 23 ms for 150 dpi renders (1374f27)
  • eliminate bounds checks in JB2 hot loops and ZP renormalize (7e94000)
  • eliminate redundant mask sampling in 3-layer composite (#14) (#27) (f601036)
  • iw44-enc: NEON forward wavelet + parallel Y/Cb/Cr + skip empty passes (#206) (d1f2765)
  • iw44: allocate chroma planes at half resolution when chroma_half=true (Issue #85) (#99) (927e7c0)
  • iw44: compact-plane wavelet for sub≥2 + correct start_scale (Issue #115) (#116) (4fc8921)
  • iw44: NEON decoder — column pass s=2/4, scatter, YCbCr, lifting (~25% to_rgb) (#207) (f570297)
  • iw44: SIMD row pass — 8 rows at a time with i32x8 (#107) (1418ff4)
  • iw44: SIMD YCbCr→RGB using wide::i32x8 (Issue #1) (#64) (abceef4)
  • iw44: SIMD-accelerate inverse wavelet transform column pass (2ac4318), closes #68
  • iw44: WASM simd128 ycbcr_raw kernels (Phase 1 of #190) (#253) (d59fcee)
  • iw44: x86_64 AVX2 ports of prelim_flags kernels (Phase 3 of #189) (#261) (0ed7a36)
  • iw44: x86_64 AVX2 ycbcr_raw kernels (Phase 1 of #189) (#251) (7f3d867)
  • jb2-enc: eliminate bounds checks from JB2 encode hot loop (#205) (5cbeaf0)
  • jb2-enc: opt-in lossy rec-7 near-duplicate substitution (Phase 4 of #224) (#256) (98fb8c7)
  • jb2-enc: per-CC accounting harness for shared-Djbz (#194 Phase 2.5) (#255) (f09bfdf)
  • jb2: bit-pack Jbm to 1 bit/pixel — 8x memory, corpus −3.9% (#187) (17f331f)
  • jb2: close performance gap vs DjVuLibre + CLI improvements (#159) (3efc430)
  • jb2: local-copy ZP state for register-allocation + hardware CLZ (0590d3c)
  • jb2: reuse scratch buffer across symbol decodes to eliminate per-symbol heap allocations (Issue #90) (#100) (12575d0)
  • jb2: shared dict cache + split_at_mut inner loop (Issue #87) (#106) (08ca0f4)
  • partial BG44 chunk decode for sub=4 renders — skip high-frequency refinement (b371e4e)
  • pdf: output_dpi option + bilevel fast path — 2× faster export (cfccbc6), closes #147
  • render: 66% speedup on 600 dpi bilevel pages (Issue #104) (#105) (8e5a2f4)
  • render: eliminate redundant mask sampling in 3-layer composite (Issue #14) (#37) (585991d)
  • render: internal row-streaming refactor (Phase 1 of #225) (#259) (3d22a59)
  • render: NEON bilinear vertical pass + 4-byte RGBX stride (#93) (b0dfdb8)
  • render: precomputed coord tables, zero-copy BG path, remove PageMapper (cf1a8e9)
  • render: x86_64 SSE2/SSSE3 fast paths for alpha fill and RGB→RGBA (#169) (0ea3f3e)
  • replace bg_subsample division with shift in composite hot path (0e0f2a3)
  • replace mask division with bit-shift in composite hot path (e4b7982)
  • use chunks_exact_mut in composite loops — eliminate per-pixel bounds checks (0176860)