`, `
`, ``) that previously produced escaped garbage is now converted to clean markdown.
* **Code classification false positives** — regular prose is no longer misclassified as Code blocks.
* **PageBreak rendering as `-----` separators** — PageBreak elements no longer pollute output with `-----` / `
`; treated as structural metadata.
* **Leptonica DPI crash** — images with 0 DPI no longer trigger an uncatchable C++ exception; DPI is validated and fixed to 72 before preprocessing.
* **Node.js `ExtractionResult.children` missing at runtime** in the published v4.7.1 binary.
* **Node.js `disable_ocr` config not respected** — `disableOcr: true` no longer produces OCR content for images.
* **PaddleOCR angle classification crash** — fixed input dimensions to match the v2 angle classifier model.
* **Chunk page numbers missing** — chunks produced with `first_page`/`last_page` null when chunking was configured without explicit `pages` config; page tracking is now auto-enabled.
***
## [4.7.1](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.7.1) - 2026-04-03
[Section titled “4.7.1 - 2026-04-03”](#471---2026-04-03)
### Added
[Section titled “Added”](#added-11)
* **Tree-sitter grammar management CLI** — new `kreuzberg tree-sitter` subcommand with `download`, `list`, `cache-dir`, and `clean` for managing grammar parsers (by language, group, or all); reads `[tree_sitter]` config from `kreuzberg.toml`.
* **Tree-sitter grammar management API** — new REST endpoints `POST /grammars/download`, `GET /grammars/list`, `GET /grammars/cache`, `DELETE /grammars/cache`.
* **Tree-sitter grammar management MCP tools** — `download_grammars`, `list_grammars`, `grammar_cache_info`, `clean_grammar_cache`.
* **Tree-sitter config startup initialization** — API and MCP servers auto-download grammars on startup when `[tree_sitter]` specifies `languages` or `groups`.
### Changed
[Section titled “Changed”](#changed-8)
* **Normalized OCR+layout pipeline** — the Tesseract+layout path now follows the same architecture as pdfium+layout, fixing destroyed paragraph structure and reading order.
* **Elixir NIF crash protection** — extraction and batch NIFs are wrapped so native-library panics (pdfium, tesseract) return `{:error, reason}` instead of crashing the BEAM VM.
### Fixed
[Section titled “Fixed”](#fixed-20)
* **hOCR parser depth tracking** — content after inner word spans is no longer silently dropped due to premature paragraph termination.
* **hOCR multi-page content loss** — content on pages 2+ is no longer dropped due to a per-page filter on per-page hOCR documents.
* **OCR batch parallelization** — page processing now scales with available CPUs (capped at 8) instead of a hardcoded 4, speeding up multi-page documents.
* **Chunking page boundary regression** — page boundaries are recomputed from rendered per-page content, fixing null `first_page`/`last_page` and a validation warning.
* **HF Hub environment variables** — respects `HF_HOME`/`HF_ENDPOINT`, fixing permission errors on Kubernetes when running as non-root.
* **PDF bridge tracing panic on multibyte characters** — no longer panics on multibyte UTF-8 (e.g. `•`).
* **Go FFI struct layout** — vendored C header was missing `children_json`, shifting all subsequent fields and reading wrong memory.
* **Java FFI struct layout** — `CExtractionResult` was missing `code_intelligence_json`, causing all Java extractions to return `success=false`.
* **PHP `__get` magic method bypass** — `elements`, `djotContent`, `document`, `ocrElements`, `children`, and `uris` returned raw JSON strings instead of deserialized arrays.
* **Ruby `disable_ocr` config** — the keyword was not parsed, so OCR ran even when explicitly disabled.
* **Node.js `ExtractionResult` parity** — `document`, `djotContent`, and `ocrElements` were omitted from JS objects when `None`; now default to `null`.
* **Node.js `convertChunk` missing `chunkType`** — the converter did not forward `chunk_type`.
* **ODT caption text extraction** — text inside `draw:text-box` (e.g. image captions) was not extracted.
* **Italian/European PDF ligature corruption** — repairs `tt`, `ti`, `tti` ligatures (e.g. `Dire*ore` → `Direttore`).
* **WASM Rayon thread pool panic** — parallel iteration now falls back to sequential on `wasm32` instead of panicking.
***
## [4.7.0](https://github.com/kreuzberg-dev/kreuzberg/releases/tag/v4.7.0) - 2026-03-30
[Section titled “4.7.0 - 2026-03-30”](#470---2026-03-30)
### Added
[Section titled “Added”](#added-12)
* **Semantic chunk labeling**: chunks now include a `chunk_type` field identifying the semantic nature of the content (e.g. `paragraph`, `heading`, `list_item`, `table_cell`, `code_block`), across all 11 language bindings.
* **Image extraction across 8 formats**: embedded images extracted as `ExtractedImage` (binary data, format, dimensions, alt text) for DOCX, PPTX, PDF, EPUB, ODT, HTML, RTF, and Markdown/MDX/Jupyter. Markdown output renders as `` with binary data in `ExtractionResult.images`.
* **Recursive OCR on embedded images**: extracted images from EPUB, ODT, HTML, and RTF are OCR’d, producing nested `ExtractionResult` in `ExtractedImage.ocr_result`.
* **PDF watermark artifact filtering** using pdfium’s `/Artifact` content marks.
* **Vertical table header reconstruction**: fixes rotated PDF table column headers extracted as reversed spaced characters.
* **Pages API for PDF extraction**: per-page content is now available via `result.pages` for PDF documents.
* **TOON wire format**: token-efficient (\~30-50% fewer tokens) JSON alternative across CLI (`--format toon`), API (`Accept: application/toon`), MCP (`response_format: "toon"`), and all 11 language bindings; losslessly convertible to/from JSON.
* **Renderer registry**: trait-based `Renderer`/`RendererRegistry` lets external crates register custom output-format plugins via `register_renderer()`.
* **URI extraction**: new `Uri` type with `UriKind` classification (Hyperlink, Image, Anchor, Citation, Reference, Email) extracted from 20+ formats, deduplicated, in `ExtractionResult.uris`.
* **Recursive email attachment extraction**: EML/MSG/PST attachments and nested `message/rfc822` parts extracted as `ArchiveEntry` children, respecting `max_archive_depth`.
* **PDF embedded file extraction**: PDF file attachments (portfolios) extracted as children (with filename sanitization, size limits, depth guards).
* **PDF bookmark/outline extraction**: document outlines extracted as URIs (page destinations as anchors, external links as hyperlinks).
* **DOCX/PPTX embedded object extraction**: OLE objects and embedded files extracted as children.
* **PPTX hyperlink extraction** from slide XML, resolved via relationship files.
* **Image path resolution for markup formats**: relative image paths in Markdown, MDX, LaTeX, RST, OrgMode, Typst, Djot, and DocBook are resolved from the filesystem (with path-traversal prevention) and extracted.
* **FictionBook image and link extraction** (base64 `