docling-project / docling-project/docling
OCR-recognized text is dropped from output for 180°-rotated images, even with force_full_page_ocr
- Dominant language
- Python
- Stars
- 66.4k
- Forks
- 4.8k
- Avg merge
- 3d 4h
- Merged PRs (30d)
- 95
Description
### Bug
For a page that is rotated 180° (upside-down scan/photo), OCR correctly detects the
orientation and correctly recognizes the text internally, but the final converted document
(`md_content` via docling-serve, or `export_to_markdown()` via the library) is **completely
empty** — the recognized text never makes it into the output.
This reproduces with a plain standalone raster image (no PDF, no rotation metadata involved —
so it's a different code path than #2038/#1822, which are about PDF `/Rotate` metadata), and
persists with `force_full_page_ocr=True`, ruling out the OCR-region/bitmap-coverage selection
logic as the cause.
I instrumented `TesseractOcrCliModel.__call__` directly (`tesseract_ocr_cli_model.py`) to trace
where the content disappears:
```
[DEBUG] entered enabled=True
[DEBUG] OSD SUCCESS doc_orientation=180
[DEBUG] df_result shape=(12, 12) # 12 words correctly recognized, e.g. "WARRANTY", "CODE:", "ZQXPHOENIX-7", "742", "This", "document", "certifies", ... — all correct, 90-96% confidence
[DEBUG] all_ocr_cells_len=12 textline_cells_len=12 has_lines=True # <- right after post_process_cells()
```
So at the point immediately after `post_process_cells()`, the page object has 12 valid,
correctly-recognized `TextCell`s with `has_lines=True`. But the final serialized document is
empty. The drop happens somewhere after the OCR stage — layout/reading-order assembly or
markdown export — not in OCR, orientation detection, or cell filtering.
This reproduces identically whether `ocr_preset` is `tesseract` (`TesseractOcrCliModel`,
confirmed via the trace above) or the default `auto`/`rapidocr` (`RapidOcrModel` — same empty
final result, though I didn't instrument that backend directly since the `tesseract` trace
already pinpoints the drop as being *after* the OCR-model stage, which should be
backend-independent).
### Related issues
This looks like the same underlying "orientation handling in the assembly pipeline" gap as:
- #1822 (rotated content silently skipped, works if re-exported via LibreOffice — still open)
- #2038 (rotation metadata not handled by `get_bitmap_rects`; closed as known/unresolved,
points at #683 and #1822)
- #639 / #1167 (added OCR-level OSD auto-rotate for tesseract backends — this is the code I
traced above; it correctly detects and corrects orientation *for OCR recognition*, but
doesn't fix the document-assembly stage downstream of it)
Given #1822 is closed by nobody and #2038 says "a general solution is still in progress," this
seems to be a known gap, but I wanted to file the specific trace since it pinpoints exactly
which stage still drops the content even after the #1167 OCR-level fix.
### Steps to reproduce
```python
from PIL import Image, ImageDraw, ImageFont
from docling.document_converter import DocumentConverter, ImageFormatOption
from docling.datamodel.pipeline_options import PdfPipelineOptions, TesseractCliOcrOptions
from docling.datamodel.base_models import InputFormat
# Build a simple upright test image, then rotate it 180°
img = Image.new("RGB", (1700, 2200), "white")
d = ImageDraw.Draw(img)
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 40)
d.text((100, 100), "WARRANTY CODE: ZQXPHOENIX-7742", fill="black", font=font)
d.text((100, 180), "This document certifies the north garage roof warranty.", fill="black", font=font)
img.rotate(180).save("/tmp/upsidedown_scan.png")
pipeline_options = PdfPipelineOptions()
pipeline_options.do_ocr = True
pipeline_options.ocr_options = TesseractCliOcrOptions(force_full_page_ocr=True)
converter = DocumentConverter(
format_options={InputFormat.IMAGE: ImageFormatOption(pipeline_options=pipeline_options)},
)
result = converter.convert("/tmp/upsidedown_scan.png")
print(result.status) # ConversionStatus.SUCCESS
print(repr(result.document.export_to_markdown())) # '' -- empty, despite OCR finding the text
```
Same result via `docling-serve`'s REST API (`POST /v1/convert/file` with
`ocr_preset=tesseract` and/or `force_full_page_ocr=true`) — `document.md_content` comes back
`""`.
### Docling version
`2.96.1` (`docling-serve:latest`, freshly pulled 2026-07-21 — confirmed this is not fixed in
the current published release)
### Python version
3.12
Contributor guide
Research direction
Start with the supplied standalone-image reproduction and trace the conversion from TesseractOcrCliModel.__call__ in tesseract_ocr_cli_model.py through post_process_cells() to export_to_markdown(). Compare the populated TextCells with the layout or reading-order assembly output; done means the recognized text appears in md_content and export_to_markdown() for the 180° image.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100