docling-project / docling-project/docling
Expose the OCR detector's input-size limit, so large-format pages aren't silently downscaled
- Dominant language
- Python
- Stars
- 66.4k
- Forks
- 4.8k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 84
Description
### Requested feature
We ingest construction drawings. The pixels are present in the files — several sheets embed a
21200 × 14800 px raster, 400 DPI on a 1346 × 940 mm sheet — and their title blocks are plainly
legible when cropped at native resolution. Through docling they come back as a few hundred garbled
characters.
`images_scale` is not the knob, although it looks like it is: it only sizes the page/picture images
docling *exports*, so raising it costs render time and changes OCR not at all. (That cost us a round
of investigation, so it may be worth a note in the docs regardless of this request.)
Docling hands the OCR engine one image per page, and every engine caps how large an image its text
detector will look at. That cap is not reachable through `PdfPipelineOptions`, and the result on a
large-format page is silent: no error, no warning, just text that comes back as noise.
For RapidOCR the binding limit is `Global.max_side_len = 2000` (`rapidocr/config.yaml`, applied in
`rapidocr/main.py`). Docling passes no override, so the whole page image is scaled down to a
2000 px longest side before detection. `OcrOptions.scale = 3.0` renders the page at 216 DPI first,
and most of that is then discarded.
Effective OCR resolution is therefore `2000 px / the page's physical long side`:
| Sheet | Effective DPI | 2.5 mm lettering is |
| --------------------- | ------------- | ------------------- |
| 210 × 297 mm (A4) | 171 DPI | 17 px |
| 420 × 594 mm (A2) | 86 DPI | 8 px |
| 841 × 1189 mm (A0) | 43 DPI | 4 px |
| 1346 × 940 mm | 38 DPI | 4 px |
Note the first row: even A4 is downscaled from the 216 DPI docling just rendered.
EasyOCR has the same shape of limit with a different number — `canvas_size = 2560` in
`easyocr/imgproc.py: resize_aspect_ratio`, which `EasyOcrModel` does not pass either.
#### Proposed solution
Expose the detector input size on `OcrOptions`, e.g.:
```python
class OcrOptions(BaseOptions):
...
detector_max_side_px: int | None = None # None = engine default
```
passed through to `Global.max_side_len` for RapidOCR and `canvas_size` for EasyOCR. Even just
plumbing the existing engine parameters through would let callers with high-resolution sources opt
into using them.
A smaller, cheaper alternative that would also help: log a warning when the page image handed to the
detector is about to be downscaled, and by how much. Right now the quality loss is completely
invisible from the outside.
### Alternatives
We now pre-tile such a page ourselves: cut it into overlapping pieces that each render inside the
detector's cap, submit them as a multi-page PDF, and let docling reassemble the text. Measured
against the sheets' own embedded text layers (six large-format drawings, `force_ocr` on, scored
token-wise), mean recall goes from **24.2% to 84.6%**, with precision rising from 13–49% to ~90%.
That is a lot of machinery outside docling to work around one unreachable constant, and the costs
are all downstream of having to rasterise:
- It can only be applied to a page carrying no text layer of its own, because rendering destroys
that text — and the decision is therefore per *page*, not per document. A mixed document (a
scanned drawing set with one born-digital sheet) has to be reassembled page by page, copying some
pages verbatim and rasterising others.
- The tiles overlap slightly so a word on a seam survives whole, which means text inside the
overlap band is read twice and appears twice in the reconstructed document.
- Rasterising a large sheet is not cheap: ~15 s and several hundred MB of peak RSS per sheet,
dominated by decoding the page's own embedded image.
None of that would be necessary if the detector could simply be told to look at a larger image.
### Related
#3499 proposes a layout-first surgical OCR mode for very high-resolution archival scans. It
overlaps in motivation, but this is a narrower ask — one option that already exists inside both
engines, just not reachable from docling — and it applies to ordinary A0/A1 drawings well short of
72 MP.
### Environment
- `docling-serve` 1.31.0 (`quay.io/docling-project/docling-serve-cpu:v1.31.0`), docling-slim 2.121.0
- OCR engine: RapidOCR via the `auto` preset, PP-OCRv6
- Numbers above were read from the running container, not inferred.
Note that I drafted this request with the help from AI.
Contributor guide
Research direction
Start with OcrOptions and trace how its values reach the OCR engines. Inspect RapidOCR's Global.max_side_len in rapidocr/main.py and EasyOCR's canvas_size in easyocr/imgproc.py: resize_aspect_ratio, then determine how the proposed option should preserve each engine's default while allowing an override. Done means callers can set one detector-size option and the selected engine receives it without changing unrelated image export behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- machine-learning
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100