|
7 | 7 | from concurrent.futures import ThreadPoolExecutor |
8 | 8 |
|
9 | 9 | import pymupdf |
| 10 | +import pytest |
10 | 11 |
|
11 | 12 | import util |
12 | 13 |
|
@@ -576,6 +577,56 @@ def test_table_header_is_computed_on_first_access(): |
576 | 577 | doc.close() |
577 | 578 |
|
578 | 579 |
|
| 580 | +@pytest.mark.parametrize("top", [120, 420]) |
| 581 | +@pytest.mark.parametrize( |
| 582 | + "bold_header, text_above, mirrored_bold, external", |
| 583 | + [ |
| 584 | + (True, True, False, False), |
| 585 | + (False, True, True, True), |
| 586 | + (False, True, False, True), |
| 587 | + (True, False, False, False), |
| 588 | + ], |
| 589 | +) |
| 590 | +def test_table_header_bold_uses_page_coordinates( |
| 591 | + top, bold_header, text_above, mirrored_bold, external |
| 592 | +): |
| 593 | + """Header boldness must use the same top-down coordinates as row bounds.""" |
| 594 | + with pymupdf.open() as doc: |
| 595 | + page = doc.new_page(width=600, height=800) |
| 596 | + for y in (top, top + 30, top + 60): |
| 597 | + page.draw_line((50, y), (350, y)) |
| 598 | + for x in (50, 200, 350): |
| 599 | + page.draw_line((x, top), (x, top + 60)) |
| 600 | + if text_above: |
| 601 | + page.insert_text((60, top - 6), "Above A", fontsize=12) |
| 602 | + page.insert_text((210, top - 6), "Above B", fontsize=12) |
| 603 | + font = "hebo" if bold_header else "helv" |
| 604 | + page.insert_text((60, top + 20), "Header A", fontsize=12, fontname=font) |
| 605 | + page.insert_text((210, top + 20), "Header B", fontsize=12, fontname=font) |
| 606 | + page.insert_text((60, top + 50), "value A", fontsize=12) |
| 607 | + page.insert_text((210, top + 50), "value B", fontsize=12) |
| 608 | + if mirrored_bold: |
| 609 | + # This text is outside the table, but its bottom-up y bounds |
| 610 | + # fall inside the top-down bounds of the first table row. |
| 611 | + page.insert_text( |
| 612 | + (60, 800 - top - 5), "Unrelated bold", fontsize=12, fontname="hebo" |
| 613 | + ) |
| 614 | + finder = page.find_tables(use_layout=False) |
| 615 | + assert len(finder.tables) == 1 |
| 616 | + table = finder.tables[0] |
| 617 | + assert table.bbox == (50, top, 350, top + 60) |
| 618 | + assert table.cells == [ |
| 619 | + (50, top, 200, top + 30), |
| 620 | + (50, top + 30, 200, top + 60), |
| 621 | + (200, top, 350, top + 30), |
| 622 | + (200, top + 30, 350, top + 60), |
| 623 | + ] |
| 624 | + assert table.extract() == [["Header A", "Header B"], ["value A", "value B"]] |
| 625 | + assert table.header.external is external |
| 626 | + expected_names = ["Above A", "Above B"] if external else ["Header A", "Header B"] |
| 627 | + assert table.header.names == expected_names |
| 628 | + |
| 629 | + |
579 | 630 | def test_add_lines(): |
580 | 631 | """Test new parameter add_lines for table recognition.""" |
581 | 632 | if platform.python_implementation() == 'GraalVM': |
|
0 commit comments