Skip to content

fix: preserve zero-width characters and ligatures in table cell extraction - #5209

Open
ManojDevarajulu wants to merge 2 commits into
pymupdf:mainfrom
ManojDevarajulu:fix-table-zero-width-ligatures
Open

ManojDevarajulu wants to merge 2 commits into
pymupdf:mainfrom
ManojDevarajulu:fix-table-zero-width-ligatures

Conversation

@ManojDevarajulu

Copy link
Copy Markdown

Fixes #5185.
Supersedes #5186 (adds automated regression test, avoids repeated object allocation in the character loop).

Problem

When quad corrections are unset (e.g. in the table layout path or when importing pymupdf4llm, which calls TOOLS.unset_quad_corrections(True)), expanded ligatures (fi, fl, ff, tt) and combining marks receive a zero-width bounding box for subsequent characters.

In extract_cells, character inclusion is evaluated using:

abs(bbox & cell) > 0.5 * abs(bbox)

For zero-area bounding boxes (abs(bbox) == 0.0), 0.0 > 0.0 evaluates to False. As a result, the second character of ligatures is silently dropped from table cells (fine-tuning -> fne-tuning, figures -> fgures, different -> diferent).

Note: Upstream main now triggers this even without pymupdf4llm because the latest source unsets quad corrections in the table layout path.

Solution

  1. Empty-bbox fallback: When bbox.is_empty (width or height <= 0), test whether the character's origin point lies inside the cell.
  2. Performance: Pre-allocate cell_rect = pymupdf.Rect(cell) once per extract_cells call instead of re-instantiating pymupdf.Rect(cell) repeatedly inside the character loop.
  3. Automated test: Added tests/test_5185.py verifying that zero-width ligature characters inside the cell are preserved ("fine") and zero-width characters outside the cell are excluded.

Verification

When quad corrections are unset (e.g. in the table layout path or when importing pymupdf4llm), expanded ligatures and combining marks receive zero-width bounding boxes. In extract_cells, the 50% bbox area overlap check evaluates to 0 > 0 (False), silently dropping the second character of ligatures (e.g. 'fine' -> 'fne').

This commit:
- Pre-allocates cell_rect once per extract_cells call.
- Falls back to testing character origin inside cell_rect when bbox is empty.
- Adds a regression test in tests/test_5185.py covering zero-width ligature retention and out-of-cell exclusion.

Fixes pymupdf#5185
@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@ManojDevarajulu

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

@ManojDevarajulu

Copy link
Copy Markdown
Author

recheck

github-actions Bot added a commit that referenced this pull request Oct 25, 2026
@ManojDevarajulu

Copy link
Copy Markdown
Author

Hey @ToukoUrsin @JorjMcKie, just checking in on this one whenever you get some time to take a look. Let me know if anything needs changing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pymupdf4llm: table cells drop the second letter of a ligature when quad corrections are unset

1 participant