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
10 changes: 9 additions & 1 deletion changes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Fixed issues:

* **Fixed** `4994 <https://github.com/pymupdf/PyMuPDF/issues/4994>`_: Dehyphenate does no longer work since 1.27.1
* **Fixed** `5054 <https://github.com/pymupdf/PyMuPDF/issues/5054>`_: clean_contents(sanitize=True) drops glyph positioning, duplicating an overprinted leading glyph (regression in 1.28.0 from 1.27.2.3)
* **Fixed** `5055 <https://github.com/pymupdf/PyMuPDF/issues/5055>`_: insert_file(...) breaks radio button groups
* **Fixed** `5059 <https://github.com/pymupdf/PyMuPDF/issues/5059>`_: Annotations disappear or move when using Page.remove_rotation() for 90 or 270 rotated pages
* **Fixed** `5067 <https://github.com/pymupdf/PyMuPDF/issues/5067>`_: Memory leak in extractBLOCKS (_as_blocks): text object reference never released
* **Fixed** `5077 <https://github.com/pymupdf/PyMuPDF/issues/5077>`_: Page.remove_rotation() takes minutes on pages with thousands of links
Expand All @@ -16,17 +17,24 @@ Fixed issues:
* **Fixed** `5101 <https://github.com/pymupdf/PyMuPDF/issues/5101>`_: Cyclic Widget /Parent makes page operations fail with FzErrorFormat: code=7: cycle in resources
* **Fixed** `5108 <https://github.com/pymupdf/PyMuPDF/issues/5108>`_: Page.clip_to_rect() drops 'sh' (shading) operators
* **Fixed** `5112 <https://github.com/pymupdf/PyMuPDF/issues/5112>`_: Stack-based buffer overflow in JM_set_annot_callout_line
* **Fixed** `5122 <https://github.com/pymupdf/PyMuPDF/issues/5122>`_: get_drawings() reports a wrong start point for a subpath following a re with negative width/height
* **Fixed** `5125 <https://github.com/pymupdf/PyMuPDF/issues/5125>`_: get_pixmap() never returns on a tagged PDF page with many MCIDs - pdf_lookup_mcid_in_mcids is a linear scan, making rendering O(n**2) per page
* **Fixed** `5140 <https://github.com/pymupdf/PyMuPDF/issues/5140>`_: Page.get_label() raises IndexError when the page precedes the first label definition
* **Fixed** `5152 <https://github.com/pymupdf/PyMuPDF/issues/5152>`_: apply_redactions() does not remove text shown with the ' operator after TL + Td (regression in 1.28)
* **Fixed** `5154 <https://github.com/pymupdf/PyMuPDF/issues/5154>`_: insert_pdf raises ValueError: <xref> is not in list when a widget's /Parent does not list it in /Kids
* **Fixed** `5165 <https://github.com/pymupdf/PyMuPDF/issues/5165>`_: Page.add_widget fails for radio buttons


Other:

* Use MuPDF-1.28.5.
* Added support for form field hierarchies.
* Added support for radio button groups.
* Added support for widget aliases.
* Fixed CVE-2026-82035.
* Fixed builds with swig-4.5.
* Fixed CVE-2026-82035.
* Fixed ignoring aspect ratio for square images.
* Fixed potential SEGV in pymupdf.Page.get_cdrawings() if callback raises exception.
* Fixed use with python-3.15.
* Remove the debug timing loop from `Annot.update()`.
* Retrospectively marked #3478 fixed in 1.25.3.
Expand Down
58 changes: 58 additions & 0 deletions tests/test_annots.py
Original file line number Diff line number Diff line change
Expand Up @@ -820,3 +820,61 @@ def test_annots_removal():
a = page.add_circle_annot((100, 100, 200, 200))
_ = page.delete_annot(a)
assert "Annots" not in doc.xref_get_keys(page.xref)


def test_5152():
def make_page(ops):
doc = pymupdf.open()
page = doc.new_page(width=300, height=200)
page.insert_text((0, 0), "x", fontname="helv") # adds a Helvetica resource
font = page.get_fonts()[0][4]
doc.update_stream(page.get_contents()[0], ops.replace("/F1", "/" + font).encode())
return doc, page

def words(page):
return [(w[4], round(w[1], 1)) for w in page.get_text("words")]

OPS = "BT /F1 12 Tf 20 150 Td 20 TL (Line1) Tj 0 -40 Td (SECRET) ' ET"
print("PyMuPDF", pymupdf.VersionBind, "MuPDF", pymupdf.mupdf_version)

results = list()

doc, page = make_page(OPS)
print("original: ", words(page))
assert words(page) == [('Line1', 37.1), ('SECRET', 97.1)]
results.append(words(page))

page.add_redact_annot(page.search_for("SECRET")[0])
page.apply_redactions()
print("after redaction: ", words(page), " <- SECRET should be gone")
results.append(words(page))
#assert words(page) == [('Line1', 37.1)]

doc, page = make_page(OPS)
page.clean_contents()
print("after clean: ", words(page), " <- positions should be unchanged")
results.append(words(page))
#assert words(page) == [('Line1', 37.1), ('SECRET', 117.1)]

doc, page = make_page(OPS.replace("(SECRET) '", "T* (SECRET) Tj"))
page.add_redact_annot(page.search_for("SECRET")[0])
page.apply_redactions()
print("T* Tj equivalent: ", words(page), " <- works")
results.append(words(page))

expected = [
[('Line1', 37.1), ('SECRET', 97.1)],
[('Line1', 37.1)],
[('Line1', 37.1), ('SECRET', 97.1)],
[('Line1', 37.1)],
]

print(f'expected')
for i in expected:
print(i)

print(f'results')
for i in results:
print(i)

assert results == expected
13 changes: 10 additions & 3 deletions tests/test_rewrite_images.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import io
import pymupdf
import os
import platform
import pymupdf
import re
import util

import PIL.Image


scriptdir = os.path.dirname(__file__)

Expand Down Expand Up @@ -44,6 +43,14 @@ def test_4918():


def test_5164():
if platform.system() == 'Windows' and int.bit_length(sys.maxsize+1) == 32:
# module `PIL` not available - see
# conftest.py:install_required_packages for details.
return
if os.environ.get('PYODIDE_ROOT'):
print('test_5164(): not running on Pyodide - No module named \'PIL\'.')
return
import PIL.Image

def colorspace_components(doc, xref):
kind, value = doc.xref_get_key(xref, "ColorSpace")
Expand Down
Loading