Document Rotation and Orientation#
Docling has a well-known, unfixed gap where pages rotated 180° (or other non-standard orientations) produce silently wrong or empty output — despite correct OCR recognition. The root cause is an architectural ordering problem: orientation detection runs inside the OCR stage, which executes after the layout and reading-order models have already processed the original, unrotated image. Confirmed present as of docling 2.115.0.
Root Cause: Pipeline Stage Ordering#
Docling's StandardPdfPipeline processes pages in this order: layout → OCR → table structure → assembly → reading order . The orientation mismatch arises because:
- Layout model calls
page.get_image(scale=1.0)on the original unrotated image and produces layout clusters in the original (potentially upside-down) coordinate space. - OCR model (
TesseractOcrCliModel) runs Tesseract OSD (--psm 0) to detect page orientation, rotates the image viaimage.rotate(-doc_orientation, expand=True), runs OCR on the rotated image, then back-transforms cell coordinates usingrotate_bounding_box(). The result: OCR cells are in corrected coordinates. - Reading-order model classifies elements by their position on what the layout model understood to be the upright page. For a 180°-rotated page, text that actually belongs to the body of the document lands at the bottom of the page image, so the layout model labels it
PAGE_FOOTER. - Export —
ReadingOrderModelassignsPAGE_HEADERandPAGE_FOOTERelements toContentLayer.FURNITURE, andexport_to_markdown()only includesContentLayer.BODYby default, so the correctly-recognized text is silently dropped.
The coordinate transformation math itself is correct. A geometric probe on the repro case confirmed clusters are exact 180° mirrors (upright l=100.67 → rotated l=859 = 1700−841), so rotate_bounding_box() is not the source of the bug.
Affected Components#
| Component | File | What goes wrong |
|---|---|---|
| Layout model | layout_model.py | Sees unrotated page; labels bottom-of-page text as PAGE_FOOTER |
| Tesseract OCR OSD | tesseract_ocr_cli_model.py L316–339 | Correctly detects and rotates image for OCR, but layout has already run |
| Bounding-box transform | orientation.py L9–65 | Mathematically correct; supports 0°/90°/180°/270° only |
| Reading-order model | readingorder_model.py L401–403 | Assigns FURNITURE layer to headers/footers; content becomes invisible to default export |
| R-tree spatial index | layout_postprocessor.py | Requires ≥20% intersection_over_self overlap; mislabeled clusters still match, so cells are assigned but under the wrong label |
RapidOcrModel does not perform image rotation at all — it passes images directly to the OCR engine without OSD — so on rotated pages it produces garbled or missing text through a different failure mode.
Reading-Order Inversion#
Even when the text does appear in output (e.g., when querying ContentLayer.FURNITURE explicitly), the reading order is wrong. The ReadingOrderPredictor uses a rule-based spatial DFS that sorts top-to-bottom by b coordinate . On a 180°-rotated page, what should be "line 1" lands at the bottom (b ≈ page_height), so the predictor sequences it last. The result is a reversed sentence order with no degraded confidence scores — a silent semantic corruption.
Workaround (Current Versions)#
Include FURNITURE layers in export to at least recover the text content (reading order will still be inverted):
from docling_core.types.doc import ContentLayer
result.document.export_to_markdown(
included_content_layers={ContentLayer.BODY, ContentLayer.FURNITURE}
)
Pre-rotate the input before passing it to Docling — orient the document upright at the source so the layout model sees correctly-oriented content. This is the most reliable workaround for the known gap.
Known Issue History#
| Issue | Status | Notes |
|---|---|---|
| #639 / #1167 | Closed | Added OCR-level OSD auto-rotate; fixes recognition, not assembly |
| #1822 | Open | Rotated content silently skipped; works if re-exported via LibreOffice |
| #2038 | Closed (unresolved) | PDF /Rotate metadata not handled by get_bitmap_rects; general fix in progress |
| #3839 | Open | 180°-rotated images: text dropped from output despite correct OCR, reproduced on 2.115.0 |
The proposed architectural fix — detecting page orientation before the layout stage and rotating the page image for all downstream models to share one orientation — requires maintainer input before implementation.
Related Topics#
- PDF Rendering and OCR Pipeline — full OCR stage detail including OSD flow
- Document Layout and Reading Order — reading-order corruption patterns and debug sorting tricks
- Page Assembly Pipeline — how clusters become
AssembledUnitelements and feed_assemble_document()