docling-project / docling-project/docling

PDF: drop-cap letter rendered as standalone text block mid-paragraph

Open
#3,883 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
66.4k
Forks
4.8k
Avg merge
2d 21h
Merged PRs (30d)
84

Description

### Bug

When a PDF uses a drop cap (an oversized initial letter at the start of a paragraph), docling extracts it as a standalone single-character text block that floats between paragraphs, corrupting the reading flow.

Example from a real PDF:

```
...previous paragraph text.

R

ealized through a combination of...
```

The "R" is a drop cap that should merge with "ealized" to form "Realized".

### Steps to reproduce

```python
from docling.document_converter import DocumentConverter

converter = DocumentConverter()
result = converter.convert("fuerea_digital_transformation_2026.pdf")
md = result.document.export_to_markdown()

# The drop cap appears as a standalone paragraph
assert "\nR\n\n" in md # Bug: "R" floating between paragraphs
```

### Expected behavior

The drop cap should be detected (single uppercase letter with font size approximately 2x or more the body text average, baseline below the next line) and merged with the first word of the following paragraph.

### Source location

`page_assemble_model.py:118-176` (`sanitize_text`) - cluster text gets normalized but no font-size-aware merge logic exists. No mention of drop cap handling anywhere in the codebase.

### Suggestion

Detect single-uppercase-letter clusters where the bounding box height is approximately 2x or more the page median line height, then merge with the next cluster's first word.

### Docling version

2.115.0

### Regression test PDF

- `fuerea_digital_transformation_2026.pdf` (1.5 MB) - two drop-cap instances (both "R") visible in the markdown output

Contributor guide

Open the contributing guide

Research direction

Start in page_assemble_model.py:118-176, especially sanitize_text, and reproduce the issue with fuerea_digital_transformation_2026.pdf using DocumentConverter and export_to_markdown(). Trace the cluster text and bounding-box data for the two standalone “R” instances. Done means both drop caps are merged with the following word without corrupting other paragraph text, with a regression test covering the PDF output.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.