docling-rs 2.2.2__tar.gz → 2.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of docling-rs might be problematic. Click here for more details.
- {docling_rs-2.2.2 → docling_rs-2.2.4}/PKG-INFO +1 -1
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/Cargo.toml +4 -4
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/cfb.rs +176 -7
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/doc.rs +0 -36
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/html.rs +25 -2
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/html_tree.rs +14 -13
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/mhtml.rs +0 -11
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/ppt.rs +0 -44
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/pptx.rs +0 -46
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/quattro.rs +0 -22
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/wps.rs +0 -17
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/xls.rs +0 -22
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-asr/Cargo.toml +3 -3
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/Cargo.toml +1 -1
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/markdown.rs +0 -2
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-onnx/Cargo.toml +2 -2
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/Cargo.toml +3 -3
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/ocr_prep.rs +15 -4
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/tesseract.rs +17 -11
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/text_layer.rs +3 -8
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/Cargo.lock +5 -5
- {docling_rs-2.2.2 → docling_rs-2.2.4}/pyproject.toml +1 -1
- {docling_rs-2.2.2 → docling_rs-2.2.4}/README.md +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/README.md +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/examples/convert.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/examples/perf_serialize.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/examples/profile_declarative.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/examples/stream.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/sample.html +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/sample.md +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/archive.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/abw.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/asciidoc.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/browser.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/chandra.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/csv.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/deepseek.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/djvu.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/doclang.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/doclang_tree.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/docling_json.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/docx.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/docx_tree.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/ebcdic.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/ebcdic_tables.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/email.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/epub.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/images.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/interchange.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/iwork.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/iwork_charts.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/jats.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/keynote.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/keynote_iwa.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/keynote_xml.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/latex.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/latex_walker.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/lotus.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/markdown.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/mc.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/md_tree.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/metafile.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/mod.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/msg.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/odf.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/odf_tree.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/officeart.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/omml.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/ooxml.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/pages.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/pages_iwa.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/pages_xml.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/rtf.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/staroffice5.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/svg.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/symbol_fonts.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/uspto.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/uspto_entities.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/visio.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/webvtt.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/wpd.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/xbrl.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/xbrl_dts.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/xlsx.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/xlsx_drawings.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/backend/xml_depth.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/chunks.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/converter.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/dclx.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/email_attachments.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/error.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/format.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/lib.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/options.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/result.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/sniff.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/source.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/stream.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/video.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling/src/vlm.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-asr/README.md +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-asr/examples/preset_check.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-asr/src/audio.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-asr/src/lib.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-asr/src/mel.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-asr/src/nemo_mel.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-asr/src/parakeet.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-asr/src/tokenizer.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-asr/src/vad.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-asr/src/whisper.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/README.md +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/assets.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/base64.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/chunker.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/confidence.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/doclang.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/doctags.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/document.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/env.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/html.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/jpeg.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/json.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/labels.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/latex.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/lib.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/mathml/mod.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/mathml/symbols.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/pandoc.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/pixel_digest.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-core/src/tree.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-onnx/README.md +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-onnx/src/lib.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/README.md +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/examples/dump_page_png.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/examples/dump_regions.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/examples/dump_stages.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/examples/extract.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/examples/layout.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/examples/render_compare.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/examples/snapshot.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/examples/text_layer.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/examples/textparse_dump.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/examples/textparse_glyphs.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/examples/tf_otsl.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/examples/word_cells.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/ffi/docling-parse-render/dparse_render.cpp +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/assemble.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/checkbox.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/dp_lines.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/dparse_render.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/enrich.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/font_style.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/heading_hierarchy.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/layout.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/lib.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/mets.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/ocr.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/ocr_det.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/orient.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/outline.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/pdf_meta.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/pdfium_backend.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/quality.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/raster/fax.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/raster/filters.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/raster/jpeg_tests.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/raster/mod.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/raster/stretch.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/reading_order.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/render/color.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/render/content.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/render/font/cmap.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/render/font/dotsection.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/render/font/encodings.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/render/font/fallback.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/render/font/mod.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/render/font/type1.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/render/function.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/render/geom.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/render/image.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/render/jpx.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/render/mod.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/render/objects.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/render/prepass.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/resample.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/scanned.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/std14.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/tableformer.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/textparse.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/tf_core.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/tf_match.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/src/timing.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/fax/shapes.g3 +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/fax/shapes.g3_2d +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/fax/shapes.g4 +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/fax/shapes.png +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/gray_444.jpg +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/gray_444.png +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/gray_progressive.jpg +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/gray_progressive.png +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_420.jpg +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_420.png +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_420_big.jpg +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_420_big.png +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_420_progressive.jpg +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_420_progressive.png +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_420_restart.jpg +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_420_restart.png +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_422.jpg +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_422.png +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_422_optimize.jpg +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_422_optimize.png +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_444.jpg +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_444.png +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_444_progressive.jpg +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpeg/rgb_444_progressive.png +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpx/gray_12x9.j2k +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpx/gray_12x9.jp2 +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpx/rgb_8x6.jp2 +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-pdf/tests/data/jpx/rgba_8x6.jp2 +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/Cargo.toml +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/README.md +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/examples/langchain/README.md +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/examples/langchain/loader_basics.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/examples/langchain/picture_description.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/examples/langchain/rag_agent.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/src/lib.rs +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/tests/data/langchain/README.md +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/tests/data/langchain/dl_doc_1.json +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/tests/data/langchain/lc_doc_chunks_1.json +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/tests/data/langchain/lc_doc_md_1.json +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/tests/test_archive.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/tests/test_chunking.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/tests/test_config.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/tests/test_dropin.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/tests/test_email.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/tests/test_langchain.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/tests/test_namespace_parity.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/docling-py/tests/test_pandoc.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/__init__.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/chunking.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/datamodel/__init__.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/datamodel/accelerator_options.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/datamodel/base_models.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/datamodel/document.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/datamodel/pipeline_options.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/document_converter.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/exceptions.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/langchain/__init__.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/langchain/loader.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/langchain/picture_description.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/models.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/options.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/pandoc.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/picture_description.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/utils/__init__.py +0 -0
- {docling_rs-2.2.2 → docling_rs-2.2.4}/python/docling_rs/utils/model_downloader.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "docling"
|
|
3
3
|
description = "DocumentConverter and format backends for docling.rs (a Rust port of docling)."
|
|
4
|
-
version = "2.2.
|
|
4
|
+
version = "2.2.4"
|
|
5
5
|
edition = "2021"
|
|
6
6
|
license = "MIT"
|
|
7
7
|
repository = "https://github.com/docling-project/docling.rs"
|
|
@@ -79,9 +79,9 @@ headless_chrome = { version = "1.0", optional = true }
|
|
|
79
79
|
# O_EXCL temp file with an unpredictable name for the browser pre-render page
|
|
80
80
|
# (avoids a predictable /tmp path a local attacker could pre-plant a symlink at).
|
|
81
81
|
tempfile = { version = "3", optional = true }
|
|
82
|
-
docling-asr = { path = "../docling-asr", version = "2.2.
|
|
83
|
-
docling-core = { path = "../docling-core", version = "2.2.
|
|
84
|
-
docling-pdf = { path = "../docling-pdf", version = "2.2.
|
|
82
|
+
docling-asr = { path = "../docling-asr", version = "2.2.4", optional = true }
|
|
83
|
+
docling-core = { path = "../docling-core", version = "2.2.4" }
|
|
84
|
+
docling-pdf = { path = "../docling-pdf", version = "2.2.4", optional = true, default-features = false }
|
|
85
85
|
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "gif", "bmp", "tiff", "webp"] }
|
|
86
86
|
mail-parser = "0.11"
|
|
87
87
|
pulldown-cmark = { version = "0.13.4", default-features = false }
|
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
//! bounded by the sector count (no cycle can loop forever) and stream sizes
|
|
9
9
|
//! are capped by the same per-part budget as OOXML parts.
|
|
10
10
|
//!
|
|
11
|
-
//! Layout ([MS-CFB]): a 512-byte header
|
|
12
|
-
//!
|
|
13
|
-
//!
|
|
11
|
+
//! Layout ([MS-CFB]): a 512-byte header (zero-padded to a whole 4096-byte
|
|
12
|
+
//! sector in a version 4 file) names the first sectors of the DIFAT (which
|
|
13
|
+
//! locates the FAT), the directory chain, and the mini FAT. Streams ≥
|
|
14
|
+
//! `mini_stream_cutoff` (4096) chain through the FAT; smaller ones live in
|
|
14
15
|
//! the *mini stream* (the root entry's stream) and chain through the mini FAT
|
|
15
16
|
//! in 64-byte mini sectors.
|
|
16
17
|
|
|
@@ -313,9 +314,14 @@ impl<'a> CompoundFile<'a> {
|
|
|
313
314
|
}
|
|
314
315
|
}
|
|
315
316
|
|
|
316
|
-
/// Byte offset of sector `n
|
|
317
|
+
/// Byte offset of sector `n`. The header occupies the file's first sector
|
|
318
|
+
/// ([MS-CFB] 2.2): 512 bytes in a version 3 file, and in a version 4 file
|
|
319
|
+
/// (4096-byte sectors) the same 512 bytes zero-padded to a whole sector, so
|
|
320
|
+
/// sector 0 starts at 4096 there — `512 + n * 4096` read every v4 structure
|
|
321
|
+
/// 3584 bytes early and rejected valid files as damaged (#623; PowerPoint
|
|
322
|
+
/// writes v4 when an edited .ppt is saved in place).
|
|
317
323
|
fn sector_offset(n: u32, sector_size: usize) -> usize {
|
|
318
|
-
512 + n as usize * sector_size
|
|
324
|
+
sector_size.max(512) + n as usize * sector_size
|
|
319
325
|
}
|
|
320
326
|
|
|
321
327
|
/// Follow a FAT chain from `start`, concatenating sectors, truncated to `size`
|
|
@@ -547,6 +553,166 @@ mod tests {
|
|
|
547
553
|
);
|
|
548
554
|
}
|
|
549
555
|
|
|
556
|
+
/// Rewrite a version 3 compound file as version 4 (#623): a 4096-byte
|
|
557
|
+
/// header sector, 4096-byte sectors, every FAT-chained stream, the mini
|
|
558
|
+
/// stream, the mini FAT and the directory re-chained in that order, the
|
|
559
|
+
/// FAT sector last. The directory gets a padding sector of unused entries
|
|
560
|
+
/// so its chain spans two sectors, and with `difat_sector` the FAT
|
|
561
|
+
/// sector is listed in a DIFAT sector instead of the header — a layout
|
|
562
|
+
/// only files of >109 FAT sectors (≈450 MB at 4 KiB) need, so it is the
|
|
563
|
+
/// only way a test reaches that read. Mini sectors stay 64 bytes in both
|
|
564
|
+
/// versions: the mini stream and mini FAT are copied verbatim.
|
|
565
|
+
fn to_v4(v3: &[u8], difat_sector: bool) -> Vec<u8> {
|
|
566
|
+
const SZ: usize = 4096;
|
|
567
|
+
let cfb = CompoundFile::open(v3).expect("valid v3 CFB");
|
|
568
|
+
assert_eq!(cfb.sector_size, 512, "source must be version 3");
|
|
569
|
+
let mut dir = read_chain(v3, &cfb.fat, u32_at(v3, 48).unwrap(), 512, u64::MAX).unwrap();
|
|
570
|
+
let mut body: Vec<u8> = Vec::new();
|
|
571
|
+
let mut fat: Vec<u32> = Vec::new();
|
|
572
|
+
let mut put = |bytes: &[u8], fat: &mut Vec<u32>| -> (u32, u32) {
|
|
573
|
+
let (start, n) = (fat.len() as u32, bytes.len().div_ceil(SZ).max(1) as u32);
|
|
574
|
+
fat.extend((1..=n).map(|i| if i == n { ENDOFCHAIN } else { start + i }));
|
|
575
|
+
body.extend_from_slice(bytes);
|
|
576
|
+
body.resize(fat.len() * SZ, 0);
|
|
577
|
+
(start, n)
|
|
578
|
+
};
|
|
579
|
+
let set = |dir: &mut Vec<u8>, i: usize, start: u32| {
|
|
580
|
+
dir[i * 128 + 116..i * 128 + 120].copy_from_slice(&start.to_le_bytes());
|
|
581
|
+
dir[i * 128 + 124..i * 128 + 128].fill(0); // v4 sizes are 64-bit
|
|
582
|
+
};
|
|
583
|
+
for (i, e) in cfb.entries.iter().enumerate() {
|
|
584
|
+
if e.object_type == 2 && e.size >= 4096 {
|
|
585
|
+
let (start, _) = put(&cfb.stream_by_index(i).unwrap(), &mut fat);
|
|
586
|
+
set(&mut dir, i, start);
|
|
587
|
+
} else if e.object_type == 5 && !cfb.mini_stream.is_empty() {
|
|
588
|
+
let (start, _) = put(&cfb.mini_stream, &mut fat);
|
|
589
|
+
set(&mut dir, i, start);
|
|
590
|
+
} else {
|
|
591
|
+
set(&mut dir, i, e.start_sector);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
let mini_fat: Vec<u8> = cfb.mini_fat.iter().flat_map(|v| v.to_le_bytes()).collect();
|
|
595
|
+
let (mfat_start, mfat_n) = put(&mini_fat, &mut fat);
|
|
596
|
+
let entries = dir.len() / 128;
|
|
597
|
+
dir.resize((entries.div_ceil(32) + 1) * SZ, 0); // unused entries: name length 0
|
|
598
|
+
let (dir_start, dir_n) = put(&dir, &mut fat);
|
|
599
|
+
// The FAT itself: its own sector (and the DIFAT sector) marked, one
|
|
600
|
+
// 1024-entry sector covers every test file.
|
|
601
|
+
let fat_sector = fat.len() as u32;
|
|
602
|
+
fat.push(0xFFFF_FFFD); // FATSECT
|
|
603
|
+
if difat_sector {
|
|
604
|
+
fat.push(0xFFFF_FFFC); // DIFSECT
|
|
605
|
+
}
|
|
606
|
+
assert!(
|
|
607
|
+
fat.len() <= SZ / 4,
|
|
608
|
+
"test file too large for one FAT sector"
|
|
609
|
+
);
|
|
610
|
+
let mut fat_bytes: Vec<u8> = fat.iter().flat_map(|v| v.to_le_bytes()).collect();
|
|
611
|
+
fat_bytes.resize(SZ, 0xFF);
|
|
612
|
+
body.extend_from_slice(&fat_bytes);
|
|
613
|
+
let mut header = vec![0u8; SZ];
|
|
614
|
+
header[..8].copy_from_slice(&HEADER_MAGIC);
|
|
615
|
+
header[24..26].copy_from_slice(&0x003Eu16.to_le_bytes());
|
|
616
|
+
header[26..28].copy_from_slice(&4u16.to_le_bytes()); // major 4
|
|
617
|
+
header[28..30].copy_from_slice(&0xFFFEu16.to_le_bytes());
|
|
618
|
+
header[30..32].copy_from_slice(&12u16.to_le_bytes()); // 4096-byte sectors
|
|
619
|
+
header[32..34].copy_from_slice(&6u16.to_le_bytes());
|
|
620
|
+
header[40..44].copy_from_slice(&dir_n.to_le_bytes()); // v4 only
|
|
621
|
+
header[44..48].copy_from_slice(&1u32.to_le_bytes());
|
|
622
|
+
header[48..52].copy_from_slice(&dir_start.to_le_bytes());
|
|
623
|
+
header[56..60].copy_from_slice(&4096u32.to_le_bytes());
|
|
624
|
+
header[60..64].copy_from_slice(&mfat_start.to_le_bytes());
|
|
625
|
+
header[64..68].copy_from_slice(&mfat_n.to_le_bytes());
|
|
626
|
+
header[76..512].fill(0xFF);
|
|
627
|
+
if difat_sector {
|
|
628
|
+
let mut difat = vec![0xFFu8; SZ];
|
|
629
|
+
difat[..4].copy_from_slice(&fat_sector.to_le_bytes());
|
|
630
|
+
difat[SZ - 4..].copy_from_slice(&ENDOFCHAIN.to_le_bytes());
|
|
631
|
+
body.extend_from_slice(&difat);
|
|
632
|
+
header[68..72].copy_from_slice(&(fat_sector + 1).to_le_bytes());
|
|
633
|
+
header[72..76].copy_from_slice(&1u32.to_le_bytes());
|
|
634
|
+
} else {
|
|
635
|
+
header[68..72].copy_from_slice(&ENDOFCHAIN.to_le_bytes());
|
|
636
|
+
header[76..80].copy_from_slice(&fat_sector.to_le_bytes());
|
|
637
|
+
}
|
|
638
|
+
header.extend_from_slice(&body);
|
|
639
|
+
header
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/// #623: version 4 files (4096-byte sectors, the header padded to one
|
|
643
|
+
/// sector) read every stream exactly as their version 3 source — FAT-
|
|
644
|
+
/// chained streams, the mini stream, a two-sector directory, a DIFAT
|
|
645
|
+
/// sector — and convert to the same document through each CFB backend
|
|
646
|
+
/// (.xls goes through calamine's own reader).
|
|
647
|
+
#[test]
|
|
648
|
+
fn v4_files_read_like_their_v3_source() {
|
|
649
|
+
use crate::{DocumentConverter, InputFormat, SourceDocument};
|
|
650
|
+
let own = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/data/");
|
|
651
|
+
let mirror = concat!(env!("CARGO_MANIFEST_DIR"), "/../../tests/data/");
|
|
652
|
+
let md = |name: &str, bytes: Vec<u8>| {
|
|
653
|
+
let ext = name.rsplit('.').next().unwrap();
|
|
654
|
+
let fmt = InputFormat::from_extension(ext).unwrap();
|
|
655
|
+
DocumentConverter::new()
|
|
656
|
+
.convert(SourceDocument::from_bytes(name, fmt, bytes))
|
|
657
|
+
.unwrap_or_else(|e| panic!("{name}: {e}"))
|
|
658
|
+
.document
|
|
659
|
+
.export_to_markdown()
|
|
660
|
+
};
|
|
661
|
+
for path in [
|
|
662
|
+
format!("{mirror}doc/sources/docx_lists.doc"),
|
|
663
|
+
format!("{own}doc/sources/embedded_word_object.doc"),
|
|
664
|
+
format!("{mirror}ppt/sources/powerpoint_sample.ppt"),
|
|
665
|
+
format!("{mirror}xls/sources/xlsx_05_table_with_title.xls"),
|
|
666
|
+
format!("{own}quattro/sources/formatcorpus_test.qpw"),
|
|
667
|
+
format!("{own}staroffice5/sources/Writer_3.1.sdw"),
|
|
668
|
+
] {
|
|
669
|
+
let name = path.rsplit('/').next().unwrap();
|
|
670
|
+
let v3 = std::fs::read(&path).unwrap();
|
|
671
|
+
let want_streams = all_streams(&CompoundFile::open(&v3).unwrap());
|
|
672
|
+
let want_md = md(name, v3.clone());
|
|
673
|
+
assert!(!want_md.trim().is_empty(), "{name}: empty baseline");
|
|
674
|
+
for difat in [false, true] {
|
|
675
|
+
let v4 = to_v4(&v3, difat);
|
|
676
|
+
let cfb = CompoundFile::open(&v4)
|
|
677
|
+
.unwrap_or_else(|| panic!("{name} v4 (difat {difat}): open failed"));
|
|
678
|
+
assert_eq!(cfb.sector_size, 4096);
|
|
679
|
+
assert!(
|
|
680
|
+
all_streams(&cfb) == want_streams,
|
|
681
|
+
"{name} v4 (difat {difat}): streams differ"
|
|
682
|
+
);
|
|
683
|
+
assert_eq!(md(name, v4), want_md, "{name} v4 (difat {difat})");
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/// The PowerPoint-written version 4 file of #623 (an edited .ppt saved
|
|
689
|
+
/// in place) opens, and losing its last sector — the end of the
|
|
690
|
+
/// `\u{5}SummaryInformation` stream — is still reported as damage to
|
|
691
|
+
/// that stream, not read as a shorter one.
|
|
692
|
+
#[test]
|
|
693
|
+
fn real_v4_file_opens_and_its_truncation_is_damage() {
|
|
694
|
+
let data = std::fs::read(concat!(
|
|
695
|
+
env!("CARGO_MANIFEST_DIR"),
|
|
696
|
+
"/tests/data/ppt/sources/ppt_cfb_v4_edit_save.ppt"
|
|
697
|
+
))
|
|
698
|
+
.unwrap();
|
|
699
|
+
assert_eq!(u16_at(&data, 26), Some(4), "fixture must be version 4");
|
|
700
|
+
let cfb = CompoundFile::open(&data).expect("valid v4 CFB");
|
|
701
|
+
assert_eq!(cfb.sector_size, 4096);
|
|
702
|
+
let len = |cfb: &CompoundFile, name| cfb.stream(name).map(|s| s.len());
|
|
703
|
+
assert_eq!(len(&cfb, "PowerPoint Document"), Some(35685));
|
|
704
|
+
assert_eq!(len(&cfb, "Current User"), Some(32)); // a mini stream entry
|
|
705
|
+
assert_eq!(len(&cfb, "\u{5}SummaryInformation"), Some(43648));
|
|
706
|
+
let short = &data[..data.len() - 4096];
|
|
707
|
+
let cfb = CompoundFile::open(short).expect("directory and FAT intact");
|
|
708
|
+
assert_eq!(len(&cfb, "PowerPoint Document"), Some(35685));
|
|
709
|
+
assert_eq!(len(&cfb, "\u{5}SummaryInformation"), None);
|
|
710
|
+
assert_eq!(
|
|
711
|
+
cfb.stream_error("ppt", "\u{5}SummaryInformation"),
|
|
712
|
+
"ppt: \u{5}SummaryInformation stream unreadable (file truncated or corrupt)"
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
|
|
550
716
|
#[test]
|
|
551
717
|
fn truncated_header_is_rejected_not_panicked() {
|
|
552
718
|
let data = std::fs::read(concat!(
|
|
@@ -554,9 +720,12 @@ mod tests {
|
|
|
554
720
|
"/../../tests/data/doc/sources/docx_lists.doc"
|
|
555
721
|
))
|
|
556
722
|
.unwrap();
|
|
557
|
-
// Every truncation point must fail cleanly
|
|
723
|
+
// Every truncation point must fail cleanly — `None`, never a panic.
|
|
558
724
|
for cut in [8, 76, 512, 700] {
|
|
559
|
-
|
|
725
|
+
assert!(
|
|
726
|
+
CompoundFile::open(&data[..cut.min(data.len())]).is_none(),
|
|
727
|
+
"cut at {cut}"
|
|
728
|
+
);
|
|
560
729
|
}
|
|
561
730
|
}
|
|
562
731
|
}
|
|
@@ -2396,42 +2396,6 @@ mod tests {
|
|
|
2396
2396
|
assert_eq!(furniture, [("page_header", "MARK_HEADER_TEXTBOX_TEXT")]);
|
|
2397
2397
|
}
|
|
2398
2398
|
|
|
2399
|
-
#[test]
|
|
2400
|
-
fn extracts_headings_lists_and_paragraphs() {
|
|
2401
|
-
let doc = DocBackend
|
|
2402
|
-
.convert(&fixture("docx_lists.doc"))
|
|
2403
|
-
.expect("converts");
|
|
2404
|
-
let headings = doc
|
|
2405
|
-
.nodes
|
|
2406
|
-
.iter()
|
|
2407
|
-
.filter(|n| matches!(n, Node::Heading { .. }))
|
|
2408
|
-
.count();
|
|
2409
|
-
let lists = doc
|
|
2410
|
-
.nodes
|
|
2411
|
-
.iter()
|
|
2412
|
-
.filter(|n| matches!(n, Node::ListItem { .. }))
|
|
2413
|
-
.count();
|
|
2414
|
-
assert!(headings > 0, "expected headings: {:?}", doc.nodes);
|
|
2415
|
-
assert!(lists > 0, "expected list items: {:?}", doc.nodes);
|
|
2416
|
-
}
|
|
2417
|
-
|
|
2418
|
-
#[test]
|
|
2419
|
-
fn extracts_tables_with_cells() {
|
|
2420
|
-
let doc = DocBackend
|
|
2421
|
-
.convert(&fixture("docx_rich_tables_01.doc"))
|
|
2422
|
-
.expect("converts");
|
|
2423
|
-
let tables: Vec<&Table> = doc
|
|
2424
|
-
.nodes
|
|
2425
|
-
.iter()
|
|
2426
|
-
.filter_map(|n| match n {
|
|
2427
|
-
Node::Table(t) => Some(t),
|
|
2428
|
-
_ => None,
|
|
2429
|
-
})
|
|
2430
|
-
.collect();
|
|
2431
|
-
assert!(!tables.is_empty(), "expected tables: {:?}", doc.nodes);
|
|
2432
|
-
assert!(tables[0].rows.len() > 1 && tables[0].rows[0].len() > 1);
|
|
2433
|
-
}
|
|
2434
|
-
|
|
2435
2399
|
/// #567: prose is Markdown-escaped like the DOCX backend's — `OBJ_DIR`
|
|
2436
2400
|
/// becomes `OBJ\_DIR` in the Markdown (the reporter's Word 2.133 and
|
|
2437
2401
|
/// DOCX outputs), and the JSON export restores the raw text.
|
|
@@ -2240,14 +2240,37 @@ fn is_row_header(cells: &[ElementRef]) -> bool {
|
|
|
2240
2240
|
/// HTML5's "rowspan=0 spans to the end of the row group" is not modelled,
|
|
2241
2241
|
/// the cell simply keeps one slot).
|
|
2242
2242
|
fn span_attr(cell: ElementRef, name: &str) -> usize {
|
|
2243
|
-
let
|
|
2243
|
+
let limit = if name == "colspan" {
|
|
2244
|
+
MAX_COLSPAN
|
|
2245
|
+
} else {
|
|
2246
|
+
MAX_ROWSPAN
|
|
2247
|
+
};
|
|
2248
|
+
span_value(cell.value().attr(name), limit)
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
/// docling's `MAX_COLSPAN` / `MAX_ROWSPAN` (`backend/utils/table_spans.py`,
|
|
2252
|
+
/// HTML's own limits): a declared span past them is clamped, so a
|
|
2253
|
+
/// `colspan="999999999"` cannot make the grid builder allocate billions of
|
|
2254
|
+
/// slots.
|
|
2255
|
+
pub(super) const MAX_COLSPAN: usize = 1000;
|
|
2256
|
+
pub(super) const MAX_ROWSPAN: usize = 65_534;
|
|
2257
|
+
|
|
2258
|
+
/// One span attribute as `_get_cell_spans` reads it — [`span_attr`]'s rule,
|
|
2259
|
+
/// clamped to `[1, limit]` (`clamp_span`); a digit run too long to parse is
|
|
2260
|
+
/// over every limit, so it is the limit. Shared with the JSON item tree
|
|
2261
|
+
/// (`html_tree`), which must see the same grid.
|
|
2262
|
+
pub(super) fn span_value(raw: Option<&str>, limit: usize) -> usize {
|
|
2263
|
+
let Some(v) = raw else {
|
|
2244
2264
|
return 1;
|
|
2245
2265
|
};
|
|
2246
2266
|
if !v.starts_with(|c: char| c.is_numeric()) {
|
|
2247
2267
|
return 1;
|
|
2248
2268
|
}
|
|
2249
2269
|
let digits: String = v.chars().take_while(|c| c.is_ascii_digit()).collect();
|
|
2250
|
-
digits.
|
|
2270
|
+
match digits.trim_start_matches('0') {
|
|
2271
|
+
"" => 1,
|
|
2272
|
+
d => d.parse::<usize>().map_or(limit, |n| n.clamp(1, limit)),
|
|
2273
|
+
}
|
|
2251
2274
|
}
|
|
2252
2275
|
|
|
2253
2276
|
/// Render a table cell to Markdown. docling treats a cell as "rich" (and
|
|
@@ -303,18 +303,15 @@ fn has_list_ancestor(elem: NodeRef<'_, HtmlNode>, boundary: NodeRef<'_, HtmlNode
|
|
|
303
303
|
}
|
|
304
304
|
|
|
305
305
|
/// upstream's `_get_cell_spans`: `colspan` / `rowspan`, each the leading
|
|
306
|
-
/// digit run when the attribute starts with a digit, else 1
|
|
306
|
+
/// digit run when the attribute starts with a digit, else 1, clamped to
|
|
307
|
+
/// `[1, MAX_*SPAN]` — the same reading as the Markdown grid (`html.rs`), so
|
|
308
|
+
/// a `rowspan="0"` keeps its slot in the JSON too (docling#4287, 2.129).
|
|
307
309
|
fn cell_spans(cell: ElementRef) -> (usize, usize) {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
} else {
|
|
314
|
-
1
|
|
315
|
-
}
|
|
316
|
-
};
|
|
317
|
-
(num("colspan"), num("rowspan"))
|
|
310
|
+
use super::html::{span_value, MAX_COLSPAN, MAX_ROWSPAN};
|
|
311
|
+
(
|
|
312
|
+
span_value(cell.value().attr("colspan"), MAX_COLSPAN),
|
|
313
|
+
span_value(cell.value().attr("rowspan"), MAX_ROWSPAN),
|
|
314
|
+
)
|
|
318
315
|
}
|
|
319
316
|
|
|
320
317
|
/// An `href` as docling's `AnnotatedText.hyperlink` serializes it: a URL
|
|
@@ -1968,11 +1965,15 @@ mod tests {
|
|
|
1968
1965
|
#[test]
|
|
1969
1966
|
fn cell_spans_follow_get_cell_spans() {
|
|
1970
1967
|
let html = Html::parse_fragment(
|
|
1971
|
-
r#"<table><tr><td colspan="3x" rowspan="0">a</td><td rowspan="x2">b</td
|
|
1968
|
+
r#"<table><tr><td colspan="3x" rowspan="0">a</td><td rowspan="x2">b</td>
|
|
1969
|
+
<td colspan="99999999999999999999999" rowspan="70000">c</td></tr></table>"#,
|
|
1972
1970
|
);
|
|
1973
1971
|
let cells: Vec<ElementRef> = html.select(sel!("td")).collect();
|
|
1974
|
-
|
|
1972
|
+
// A zero span keeps one slot (docling#4287), not none.
|
|
1973
|
+
assert_eq!(cell_spans(cells[0]), (3, 1));
|
|
1975
1974
|
assert_eq!(cell_spans(cells[1]), (1, 1));
|
|
1975
|
+
// Past HTML's limits: clamped, even past `usize`.
|
|
1976
|
+
assert_eq!(cell_spans(cells[2]), (1000, 65_534));
|
|
1976
1977
|
}
|
|
1977
1978
|
|
|
1978
1979
|
/// The shape upstream gives a small page: the `<title>` and the prelude
|
|
@@ -641,17 +641,6 @@ mod tests {
|
|
|
641
641
|
assert!(md(data).contains("Привет, мир"));
|
|
642
642
|
}
|
|
643
643
|
|
|
644
|
-
#[test]
|
|
645
|
-
fn real_blink_fixture_decodes_quoted_printable_html() {
|
|
646
|
-
// docling's `tests/data/mhtml/sources/example.mhtml`, mirrored (#386).
|
|
647
|
-
let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
|
|
648
|
-
.join("../../tests/data/mhtml/sources/example.mhtml");
|
|
649
|
-
let bytes = std::fs::read(path).expect("mirrored upstream fixture");
|
|
650
|
-
let markdown = md(bytes);
|
|
651
|
-
assert!(markdown.contains("# Example Domain"), "{markdown}");
|
|
652
|
-
assert!(markdown.contains("[Learn more](https://iana.org/domains/example)"));
|
|
653
|
-
}
|
|
654
|
-
|
|
655
644
|
#[test]
|
|
656
645
|
fn embedded_images_resolve_by_location_and_cid() {
|
|
657
646
|
let parts = png_part(
|
|
@@ -792,50 +792,6 @@ mod tests {
|
|
|
792
792
|
use super::*;
|
|
793
793
|
use crate::InputFormat;
|
|
794
794
|
|
|
795
|
-
fn fixture(name: &str) -> SourceDocument {
|
|
796
|
-
let path = format!(
|
|
797
|
-
"{}/../../tests/data/ppt/sources/{name}",
|
|
798
|
-
env!("CARGO_MANIFEST_DIR")
|
|
799
|
-
);
|
|
800
|
-
let bytes = std::fs::read(&path).expect("fixture exists");
|
|
801
|
-
SourceDocument::from_bytes(name, InputFormat::Ppt, bytes)
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
#[test]
|
|
805
|
-
fn extracts_slide_titles_and_text() {
|
|
806
|
-
let doc = PptBackend
|
|
807
|
-
.convert(&fixture("powerpoint_sample.ppt"))
|
|
808
|
-
.expect("converts");
|
|
809
|
-
let headings = doc
|
|
810
|
-
.nodes
|
|
811
|
-
.iter()
|
|
812
|
-
.filter(|n| matches!(n, Node::Heading { .. }))
|
|
813
|
-
.count();
|
|
814
|
-
assert!(headings > 0, "expected slide titles: {:?}", doc.nodes);
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
#[test]
|
|
818
|
-
fn reconstructs_grouped_shapes_into_a_table() {
|
|
819
|
-
let doc = PptBackend
|
|
820
|
-
.convert(&fixture("powerpoint_sample.ppt"))
|
|
821
|
-
.expect("converts");
|
|
822
|
-
let tables: Vec<&Table> = doc
|
|
823
|
-
.nodes
|
|
824
|
-
.iter()
|
|
825
|
-
.filter_map(|n| match n {
|
|
826
|
-
Node::Table(t) => Some(t),
|
|
827
|
-
_ => None,
|
|
828
|
-
})
|
|
829
|
-
.collect();
|
|
830
|
-
assert!(!tables.is_empty(), "expected a reconstructed table");
|
|
831
|
-
let t = tables[0];
|
|
832
|
-
assert!(
|
|
833
|
-
t.rows.len() >= 2 && t.rows[0].len() >= 2,
|
|
834
|
-
"grid too small: {:?}",
|
|
835
|
-
t.rows
|
|
836
|
-
);
|
|
837
|
-
}
|
|
838
|
-
|
|
839
795
|
#[test]
|
|
840
796
|
fn grid_table_rejects_a_column_of_shapes() {
|
|
841
797
|
// Four stacked shapes (one column) must NOT read as a table.
|
|
@@ -1299,52 +1299,6 @@ fn cell_text(tc: XmlNode) -> String {
|
|
|
1299
1299
|
fn descendant<'a, 'input>(node: XmlNode<'a, 'input>, name: &str) -> Option<XmlNode<'a, 'input>> {
|
|
1300
1300
|
node.descendants().find(|n| n.has_tag_name(name))
|
|
1301
1301
|
}
|
|
1302
|
-
#[cfg(test)]
|
|
1303
|
-
mod chart_tests {
|
|
1304
|
-
use super::*;
|
|
1305
|
-
use crate::backend::DeclarativeBackend;
|
|
1306
|
-
use crate::{InputFormat, SourceDocument};
|
|
1307
|
-
|
|
1308
|
-
/// docling PR #3794: a native chart frame becomes a classified chart with
|
|
1309
|
-
/// its cached data grid and the chart title as the caption.
|
|
1310
|
-
#[test]
|
|
1311
|
-
fn native_chart_yields_classified_data_grid() {
|
|
1312
|
-
let path = format!(
|
|
1313
|
-
"{}/../../tests/data/pptx/sources/pptx_chart.pptx",
|
|
1314
|
-
env!("CARGO_MANIFEST_DIR")
|
|
1315
|
-
);
|
|
1316
|
-
let bytes = std::fs::read(&path).expect("fixture exists");
|
|
1317
|
-
let src = SourceDocument::from_bytes("c.pptx", InputFormat::Pptx, bytes);
|
|
1318
|
-
let doc = PptxBackend.convert(&src).expect("converts");
|
|
1319
|
-
let chart = doc
|
|
1320
|
-
.nodes
|
|
1321
|
-
.iter()
|
|
1322
|
-
// Slide content hangs off the slide's own group (#402).
|
|
1323
|
-
.flat_map(|n| match n {
|
|
1324
|
-
Node::Group { children, .. } => children.as_slice(),
|
|
1325
|
-
other => std::slice::from_ref(other),
|
|
1326
|
-
})
|
|
1327
|
-
.find_map(|n| match n {
|
|
1328
|
-
Node::Chart {
|
|
1329
|
-
kind,
|
|
1330
|
-
table,
|
|
1331
|
-
caption,
|
|
1332
|
-
..
|
|
1333
|
-
} => Some((kind.clone(), table.clone(), caption.clone())),
|
|
1334
|
-
_ => None,
|
|
1335
|
-
})
|
|
1336
|
-
.expect("a chart node");
|
|
1337
|
-
assert_eq!(chart.0, "bar_chart");
|
|
1338
|
-
assert_eq!(
|
|
1339
|
-
chart.2.as_deref(),
|
|
1340
|
-
Some("Wild Duck Observations by Year"),
|
|
1341
|
-
"chart title as caption"
|
|
1342
|
-
);
|
|
1343
|
-
assert_eq!(chart.1.rows[0][1], "Freshwater Ducks");
|
|
1344
|
-
assert_eq!(chart.1.rows[1], vec!["2019", "120", "80"]);
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
1302
|
#[cfg(test)]
|
|
1349
1303
|
mod list_marker_tests {
|
|
1350
1304
|
use super::{list_kind, Placeholder};
|
|
@@ -707,26 +707,4 @@ mod tests {
|
|
|
707
707
|
assert_eq!(g[&(3, 1)], "1.5");
|
|
708
708
|
assert_eq!(g[&(4, 1)], "-2");
|
|
709
709
|
}
|
|
710
|
-
|
|
711
|
-
#[test]
|
|
712
|
-
fn corpus_samples_convert() {
|
|
713
|
-
let dir =
|
|
714
|
-
std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/data/quattro/sources");
|
|
715
|
-
for (f, needle) in [
|
|
716
|
-
("formatcorpus_ksbase.wq1", "OBSERV"),
|
|
717
|
-
(
|
|
718
|
-
"formatcorpus_ks4000.wq2",
|
|
719
|
-
"SATURATED HYDRAULIC CONDUCTIVITY",
|
|
720
|
-
),
|
|
721
|
-
("formatcorpus_test.wb1", "| X |"),
|
|
722
|
-
("formatcorpus_test.wb2", "| X |"),
|
|
723
|
-
("formatcorpus_test.wb3", "This is an example spreadsheet"),
|
|
724
|
-
("formatcorpus_test.qpw", "This is an example spreadsheet"),
|
|
725
|
-
] {
|
|
726
|
-
let bytes = std::fs::read(dir.join(f)).unwrap();
|
|
727
|
-
let doc = convert(bytes).unwrap_or_else(|e| panic!("{f}: {e}"));
|
|
728
|
-
let md = md(&doc);
|
|
729
|
-
assert!(md.contains(needle), "{f}:\n{md}");
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
710
|
}
|
|
@@ -1105,21 +1105,4 @@ mod tests {
|
|
|
1105
1105
|
.to_string();
|
|
1106
1106
|
assert!(e.contains("not a Microsoft Works document"), "{e}");
|
|
1107
1107
|
}
|
|
1108
|
-
|
|
1109
|
-
#[test]
|
|
1110
|
-
fn libreoffice_fixtures_parse() {
|
|
1111
|
-
// LibreOffice's libwps smoke files are near-empty documents; they
|
|
1112
|
-
// must at least parse and detect their generation.
|
|
1113
|
-
let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/data/works/sources");
|
|
1114
|
-
for f in [
|
|
1115
|
-
"works2_dos.wps",
|
|
1116
|
-
"works3.wps",
|
|
1117
|
-
"works45.wps",
|
|
1118
|
-
"works5.wps",
|
|
1119
|
-
"works6.wps",
|
|
1120
|
-
] {
|
|
1121
|
-
let bytes = std::fs::read(dir.join(f)).unwrap();
|
|
1122
|
-
convert(bytes).unwrap_or_else(|e| panic!("{f}: {e}"));
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
1108
|
}
|
|
@@ -124,28 +124,6 @@ mod tests {
|
|
|
124
124
|
use super::*;
|
|
125
125
|
use crate::InputFormat;
|
|
126
126
|
|
|
127
|
-
fn fixture(name: &str) -> SourceDocument {
|
|
128
|
-
let path = format!(
|
|
129
|
-
"{}/../../tests/data/xls/sources/{name}",
|
|
130
|
-
env!("CARGO_MANIFEST_DIR")
|
|
131
|
-
);
|
|
132
|
-
let bytes = std::fs::read(&path).expect("fixture exists");
|
|
133
|
-
SourceDocument::from_bytes(name, InputFormat::Xls, bytes)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
#[test]
|
|
137
|
-
fn parses_xls_tables_like_the_xlsx_twin() {
|
|
138
|
-
let doc = XlsBackend::default()
|
|
139
|
-
.convert(&fixture("xlsx_01.xls"))
|
|
140
|
-
.expect("converts");
|
|
141
|
-
let tables: Vec<_> = doc
|
|
142
|
-
.nodes
|
|
143
|
-
.iter()
|
|
144
|
-
.filter(|n| matches!(n, Node::Table(_)))
|
|
145
|
-
.collect();
|
|
146
|
-
assert!(!tables.is_empty(), "expected tables, got: {:?}", doc.nodes);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
127
|
#[test]
|
|
150
128
|
fn garbage_is_an_error_not_a_panic() {
|
|
151
129
|
let src = SourceDocument::from_bytes("x.xls", InputFormat::Xls, vec![0u8; 64]);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "docling-asr"
|
|
3
3
|
description = "Audio/ASR pipeline for docling.rs (Whisper via ONNX; a Rust port of docling's ASR pipeline)."
|
|
4
|
-
version = "2.2.
|
|
4
|
+
version = "2.2.4"
|
|
5
5
|
edition = "2021"
|
|
6
6
|
license = "MIT"
|
|
7
7
|
repository = "https://github.com/docling-project/docling.rs"
|
|
@@ -25,10 +25,10 @@ xnnpack = ["docling-onnx/xnnpack"]
|
|
|
25
25
|
ort-load-dynamic = ["docling-onnx/load-dynamic", "ort/load-dynamic"]
|
|
26
26
|
|
|
27
27
|
[dependencies]
|
|
28
|
-
docling-core = { path = "../docling-core", version = "2.2.
|
|
28
|
+
docling-core = { path = "../docling-core", version = "2.2.4" }
|
|
29
29
|
# Shared ONNX execution-provider selection (DOCLING_RS_EP, #288) — routes the
|
|
30
30
|
# Whisper encoder/decoder sessions through the same switch as docling-pdf.
|
|
31
|
-
docling-onnx = { path = "../docling-onnx", version = "2.2.
|
|
31
|
+
docling-onnx = { path = "../docling-onnx", version = "2.2.4" }
|
|
32
32
|
# Same ort as docling-pdf so the workspace keeps a single ONNX runtime.
|
|
33
33
|
ort = { version = "2.0.0-rc.13", default-features = false, features = ["std", "download-binaries", "tls-rustls"] }
|
|
34
34
|
serde_json = "1"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "docling-core"
|
|
3
3
|
description = "Core DoclingDocument data model and serializers for docling.rs (a Rust port of docling)."
|
|
4
|
-
version = "2.2.
|
|
4
|
+
version = "2.2.4"
|
|
5
5
|
edition = "2021"
|
|
6
6
|
license = "MIT"
|
|
7
7
|
repository = "https://github.com/docling-project/docling.rs"
|
|
@@ -2628,7 +2628,6 @@ mod tests {
|
|
|
2628
2628
|
/// buffered export.
|
|
2629
2629
|
#[test]
|
|
2630
2630
|
fn streamer_matches_buffered_export_with_options() {
|
|
2631
|
-
use crate::document::ContentLayer;
|
|
2632
2631
|
let doc = options_doc();
|
|
2633
2632
|
let options = MarkdownExportOptions {
|
|
2634
2633
|
layers: ContentLayers::ALL,
|
|
@@ -2651,7 +2650,6 @@ mod tests {
|
|
|
2651
2650
|
buffered.contains("(img)") && buffered.contains("R&D _ report"),
|
|
2652
2651
|
"{buffered}"
|
|
2653
2652
|
);
|
|
2654
|
-
let _ = ContentLayer::Notes;
|
|
2655
2653
|
}
|
|
2656
2654
|
|
|
2657
2655
|
/// #613: the plain export of a document holding every decoration the
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "docling-onnx"
|
|
3
3
|
description = "Shared ONNX Runtime execution-provider selection for docling.rs (DOCLING_RS_EP)."
|
|
4
|
-
version = "2.2.
|
|
4
|
+
version = "2.2.4"
|
|
5
5
|
edition = "2021"
|
|
6
6
|
license = "MIT"
|
|
7
7
|
repository = "https://github.com/docling-project/docling.rs"
|
|
@@ -41,7 +41,7 @@ xnnpack = ["ort/xnnpack"]
|
|
|
41
41
|
load-dynamic = ["ort/load-dynamic", "dep:libloading"]
|
|
42
42
|
|
|
43
43
|
[dependencies]
|
|
44
|
-
docling-core = { path = "../docling-core", version = "2.2.
|
|
44
|
+
docling-core = { path = "../docling-core", version = "2.2.4" }
|
|
45
45
|
# Same ort build as docling-pdf/docling-asr so the workspace keeps a single
|
|
46
46
|
# ONNX Runtime.
|
|
47
47
|
ort = { version = "2.0.0-rc.13", default-features = false, features = ["std", "download-binaries", "tls-rustls"] }
|