docling-project / docling-project/docling
Add configurable page padding to improve table detection for edge-to-edge tables
- Dominant language
- Python
- Stars
- 66.4k
- Forks
- 4.8k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 84
Description
The LayoutModel (Heron/Egret) fails to detect tables that extend to or near the page edges. When there is insufficient margin between a table boundary and the page boundary, the model cannot distinguish them. TableFormer never receives the table region, and structured table content is extracted as unstructured text -- or lost entirely.
This is not a rare edge case. Many real-world documents use the full page width (or smal margin) for tables.
## The fix is simple: padding works
We tested multiple PDFs with and without external L+R padding (40pt / ~14mm white borders added left and right via pypdf before sending to Docling). Results:
| Document type | Tables (no padding) | Tables (with padding) | Effect |
|---------------|--------------------|-----------------------|--------|
| Full-page table | 1 | **2** | Missed table now detected |
| Dense form with edge tables | partial | **complete** | Edge table fully captured (715 tok vs 19 tok fragment) |
| Table-heavy, good margins | identical | identical | No effect |
| Table-heavy, centered | identical | identical | No effect |
| Text-only | 0 | 0 | No effect (identical) |
Adding padding to page images **recovers tables that LayoutModel completely misses**. A 715-token table was reduced to a 19-token fragment without padding -- 97% data loss for that section. No amount of downstream processing can fix a table that LayoutModel never detected.
However, our external workaround re-encodes the entire PDF via pypdf, which changes the internal document structure. This caused regressions in some documents (complete page data loss, table detection downgrades) and adds 44-100% processing time.
**A native Docling solution at the image level would get the benefits without the regressions**, because it only adds white pixels to the rendered page image -- no PDF structure changes, no re-encoding overhead. Bounding box coordinates would need to be adjusted for the padding offset in downstream models, but this is straightforward with known padding values.
## The infrastructure already exists (but was never completed)
**TFPredictor reads padding config but never applies it:**
`docling-ibm-models/tableformer/data_management/tf_predictor.py`:
```python
# Lines 117-118: Config is READ but never USED
self._padding = config["predict"].get("padding", False) # Always False
self._padding_size = config["predict"].get("padding_size", 10) # Never used
```
The `tm_config.json` already contains `"padding": false, "padding_size": 50`. There is also:
- `_depad_bboxes()` method (lines 324-376) for removing padding from bounding boxes -- **exists but is never called**
- `_prepare_image()` (lines 995-1022) squashes images to 448x448 **ignoring `self._padding` entirely**
- Dataset config has `"padding_mode": "null"` and `"padding_color": [0, 0, 0]`
The infrastructure was designed (config reading, bbox depadding, dataset padding config) but the actual image padding step was never implemented.
The experimental `TableCropsLayoutModel` (PR #2669) treats the entire page as a single table -- useful for pre-cropped table images, but not applicable to multi-element pages.
## Proposed solution: configurable per-side page padding
Add a `page_padding` option to `PdfPipelineOptions` that adds white padding to rendered page images before layout detection:
```python
page_padding: Annotated[
Union[int, tuple[int, int], tuple[int, int, int, int]],
Field(
description="Padding in pixels added around page images before layout detection. "
"Helps detect tables that extend to page edges. "
"int: uniform all sides. "
"tuple(h, w): vertical/horizontal. "
"tuple(top, right, bottom, left): per-side. "
"0 = disabled.",
),
] = 0
```
Examples:
- `page_padding=40` -- uniform 40px all sides
- `page_padding=(0, 40)` -- L+R only (our tested configuration)
- `page_padding=(10, 40, 10, 40)` -- individual per-side control
Best insertion point: `LayoutModel.predict_layout()` before line 170 -- targeted to layout detection only, no side effects on OCR or other models. Padding offsets need to be subtracted from predicted bounding boxes before passing to downstream models.
## What padding does NOT help with
- Form-style layouts where fields are not grouped into tables -- `pipeline: vlm` is the better approach
- Documents where tables already have sufficient margins (no change, as expected)
- Text-only documents (identical output, as expected)
## External workaround (current)
```python
from pypdf import PdfReader, PdfWriter
import io
def add_padding_to_pdf(pdf_bytes: bytes, padding: float = 40.0) -> bytes:
reader = PdfReader(io.BytesIO(pdf_bytes))
writer = PdfWriter()
for page in reader.pages:
new_w = float(page.mediabox.width) + 2 * padding
new_h = float(page.mediabox.height) + 2 * padding
blank = writer.add_blank_page(width=new_w, height=new_h)
blank.merge_translated_page(page, tx=padding, ty=padding)
output = io.BytesIO()
writer.write(output)
return output.getvalue()
```
This proves the concept but is not production-viable due to PDF re-encoding side effects.
## Environment
Docling v1.11.0 (docling-serve), default settings (pypdfium2 backend, Heron LayoutModel, table_mode=accurate)
## Related
- #56 -- TableFormer gives different output for slight bbox padding changes (open since Dec 2024, no response)
- #278 -- Long tables, fields being truncated
- #1306 -- Wrong detection for wide table rows
- #2073 -- Failing table structure identification
- #2203 -- Empty tables with Heron Layout Model
Contributor guide
Assessment
This issue has not been assessed yet.