diff --git a/src/table.py b/src/table.py index eb3aaf412..5e6e873d9 100644 --- a/src/table.py +++ b/src/table.py @@ -348,6 +348,7 @@ def extract_cells(textpage, cell, markdown=False): A string with the text extracted from the cell. """ text = "" + cell_rect = pymupdf.Rect(cell) for block in textpage.extractRAWDICT()["blocks"]: if block["type"] != 0: continue @@ -388,12 +389,21 @@ def extract_cells(textpage, cell, markdown=False): ): continue # skip spans outside cell - # only include chars with more than 50% bbox overlap + # only include chars with more than 50% bbox overlap. + # A char with an empty bbox (e.g. second character of an expanded + # ligature with quad corrections unset, or a zero-width combining mark) + # has no area; fall back to testing if its origin is inside the cell: + # issue #5185. span_text = "" for char in span["chars"]: this_char = char["c"] bbox = pymupdf.Rect(char["bbox"]) - if abs(bbox & cell) > 0.5 * abs(bbox): + if bbox.is_empty: + in_cell = pymupdf.Point(char["origin"]) in cell_rect + else: + in_cell = abs(bbox & cell_rect) > 0.5 * abs(bbox) + + if in_cell: span_text += this_char elif this_char in white_spaces: span_text += " " diff --git a/tests/test_5185.py b/tests/test_5185.py new file mode 100644 index 000000000..4ef775e31 --- /dev/null +++ b/tests/test_5185.py @@ -0,0 +1,34 @@ +""" +Regression test for issue #5185: table cell extraction dropped characters with +an empty bbox, e.g. the second character of an expanded ligature when quad +corrections are unset ("fine" became "fne"). +""" + +from pymupdf.table import extract_cells + + +class _TextPage: + """Minimal stand-in for a TextPage, providing extractRAWDICT() only.""" + + def __init__(self, chars): + bbox = (0, 0, 500, 30) + span = {"bbox": bbox, "flags": 0, "char_flags": 0, "chars": chars} + line = {"bbox": bbox, "dir": (1, 0), "spans": [span]} + self.rawdict = {"blocks": [{"type": 0, "bbox": bbox, "lines": [line]}]} + + def extractRAWDICT(self): + return self.rawdict + + +def test_5185(): + cell = (0, 0, 100, 30) + chars = [ + {"c": "f", "bbox": (10, 10, 15, 20), "origin": (10, 18)}, + # zero-width bbox of the expanded "fi" ligature, inside the cell + {"c": "i", "bbox": (15, 10, 15, 20), "origin": (15, 18)}, + {"c": "n", "bbox": (15, 10, 20, 20), "origin": (15, 18)}, + {"c": "e", "bbox": (20, 10, 25, 20), "origin": (20, 18)}, + # zero-width char outside the cell must still be excluded + {"c": "x", "bbox": (150, 10, 150, 20), "origin": (150, 18)}, + ] + assert extract_cells(_TextPage(chars), cell) == "fine"