Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions changes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@ Change Log
==========


Fixed issues:

* **Fixed** `4670 <https://github.com/pymupdf/PyMuPDF/issues/4670>`_: scrub fails to remove hidden text after clean_contents stopped including line breaks (\u2265 1.24.0)
* **Fixed** `4943 <https://github.com/pymupdf/PyMuPDF/issues/4943>`_: enh: applying redactions with image cropping for currently unsupported colorspaces
* **Fixed** `5030 <https://github.com/pymupdf/PyMuPDF/issues/5030>`_: find_tables() with layout enabled can return a zero-cell Table, and Table.bbox then raises "ValueError: min() iterable argument is empty"
* **Fixed** `5044 <https://github.com/pymupdf/PyMuPDF/issues/5044>`_: Outline (TOC) parsing bug
* **Fixed** `5049 <https://github.com/pymupdf/PyMuPDF/issues/5049>`_: font subsetting segfaults in 1.28.0, regression from 1.27.2.2 #5049
* **Fixed** `5042 <https://github.com/pymupdf/PyMuPDF/issues/5042>`_: Page.get_texttrace() leaks None references \u2014 Fatal Python error (none_dealloc) in long-running processes (1.27.2.3 & 1.28.0)


Other:

* Output warning when legacy `fitz` module is imported.
* Cope better with markdown containing illegal utf8 sequences.
* Fixed building with PYMUPDF_SETUP_MUPDF_VS_UPGRADE.
* pymupdf.Page.find_tables():
* new args `use_layout: bool = True` `union: bool = False` `refine: bool = False`.
* Improved speed.


**Changes in version 1.28.0** (2026-06-29)

Fixed issues:
Expand All @@ -21,6 +41,7 @@ Other:
* Support Windows builds with free thread python.
* pymupdf.Document.save() now saves non-PDF documents in PDF format.
* New method pymupdf.Document.apply_css().
* Pyodide wheel is available on pypi.org.


**Changes in version 1.27.2.3** (2026-04-24)
Expand Down
3 changes: 2 additions & 1 deletion src/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -2983,7 +2983,8 @@ def find_tables(
tp2 = page.get_textpage(flags=TABLE_DETECTOR_FLAGS)
for rect in my_boxes:
cells = make_table_from_bbox(tp2, word_rects, rect) # pylint: disable=E0606
tbf.tables.append(Table(page, cells))
if cells:
tbf.tables.append(Table(page, cells))
if refine:
# Grid refinement + reconstruction. Runs while the page is still
# derotated (before the finally block resets rotation) so word and
Expand Down
Binary file added tests/resources/test_4936.pdf
Binary file not shown.
Binary file added tests/resources/test_4943.pdf
Binary file not shown.
37 changes: 37 additions & 0 deletions tests/test_annots.py
Original file line number Diff line number Diff line change
Expand Up @@ -753,3 +753,40 @@ def test_5033():
annot.update()
annot.set_rotation(0)
annot.update()


def test_4943():
if pymupdf.pymupdf_version_tuple == (1, 28, 0) and pymupdf.mupdf_version_tuple == (1, 29, 0):
print(f'test_4943():not running because pymupdf-1.28.0 has ambiguous mupdf version.')
return
path = os.path.normpath(f'{__file__}/../../tests/resources/test_4943.pdf')
with pymupdf.open(path) as document:
page = document[0]
page.add_redact_annot(page.rect)
expect_fail = pymupdf.mupdf_version_tuple <= (1, 28, 0)
print(f'{pymupdf.pymupdf_version_tuple=} {pymupdf.mupdf_version_tuple=} {expect_fail=}.')
try:
page.apply_redactions(images=pymupdf.PDF_REDACT_IMAGE_PIXELS)
except pymupdf.mupdf.FzErrorArgument as e:
print(f'Exception: {e}')
assert expect_fail, f'{pymupdf.mupdf_version_tuple=} {pymupdf.pymupdf_version_tuple=}'
else:
print(f'No exception.')
assert not expect_fail, f'{pymupdf.mupdf_version_tuple=} {pymupdf.pymupdf_version_tuple=}'


def test_4936():
path = os.path.normpath(f'{__file__}/../../tests/resources/test_4936.pdf')
with pymupdf.open(path) as document:
page = document[0]
rect = pymupdf.Rect(
pymupdf.FZ_MIN_INF_RECT,
pymupdf.FZ_MIN_INF_RECT,
pymupdf.FZ_MAX_INF_RECT,
pymupdf.FZ_MAX_INF_RECT,
)
page.add_redact_annot(rect, fill=False)
page.apply_redactions(graphics=2)
drawings = page.get_drawings()
print(f'{len(drawings)=}')
assert len(drawings) == 0
3 changes: 3 additions & 0 deletions tests/test_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,9 @@ def test_find_tables_state_is_call_local_for_threads():
if platform.python_implementation() == "GraalVM":
print("test_find_tables_state_is_call_local_for_threads(): not running because slow on GraalVM.")
return
if os.environ.get('PYODIDE_ROOT'):
print('test_find_tables_state_is_call_local_for_threads(): not running on Pyodide - threads unsupported.')
return

pdf_bytes = _make_find_tables_state_doc()
expected = _find_tables_use_layout_false_signature(pdf_bytes)
Expand Down
Loading