From a8cafe4c0eea4909084288b09c9c3ac4e63ef8df Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 3 Sep 2026 18:23:08 +1000 Subject: [PATCH 1/4] Simplify code --- src/PIL/ImageQt.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/PIL/ImageQt.py b/src/PIL/ImageQt.py index ed747ffefa7..746e66e8aee 100644 --- a/src/PIL/ImageQt.py +++ b/src/PIL/ImageQt.py @@ -135,10 +135,9 @@ def align8to32(bytes: bytes, width: int, mode: str) -> bytes: def _aligned_stride(width: int, mode: str) -> int: # Compute the stride (scanline size) in bytes when aligned - # to Qt's requirement that scanlines be aligned to 4 bytes. + # to Qt's requirement that scanlines be aligned to 32 bits. mode_bpp = {"1": 1, "L": 8, "P": 8, "I;16": 16} - bytes_per_line = (mode_bpp[mode] * width + 7) // 8 - return (bytes_per_line + 3) & ~3 + return (mode_bpp[mode] * width + 31) // 32 * (32 // 8) def _toqclass_helper(im: Image.Image | str | QByteArray) -> dict[str, Any]: From 5387ffdfc90c1d7c01358a8f1773e991f86e823e Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 3 Sep 2026 18:30:42 +1000 Subject: [PATCH 2/4] Document deprecation --- Tests/test_imageqt.py | 2 +- docs/deprecations.rst | 10 +++++++++- docs/releasenotes/13.0.0.rst | 7 ++++--- src/PIL/ImageQt.py | 4 +--- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Tests/test_imageqt.py b/Tests/test_imageqt.py index 7d56ce5f101..d139b59bf5d 100644 --- a/Tests/test_imageqt.py +++ b/Tests/test_imageqt.py @@ -58,7 +58,7 @@ def test_closed_file() -> None: def test_deprecated_align8to32_matches_new_impl() -> None: im = hopper("P").resize((113, 113)) # size causes alignment issues w, h = im.size - with pytest.warns(DeprecationWarning, match="Implement"): + with pytest.warns(DeprecationWarning, match="ImageQt.align8to32"): old_b = ImageQt.align8to32(im.tobytes(), w, im.mode) stride = ImageQt._aligned_stride(w, im.mode) new_b = im.tobytes("raw", im.mode, stride) diff --git a/docs/deprecations.rst b/docs/deprecations.rst index 70745104483..2d56df15da8 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -21,7 +21,7 @@ ExifTags.IFD.Makernote ``ExifTags.IFD.MakerNote``. Image getdata() -~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^ .. deprecated:: 12.1.0 @@ -30,6 +30,14 @@ Image getdata() identical, except that it returns a tuple of pixel values, instead of an internal Pillow data type. +ImageQt align8to32() +^^^^^^^^^^^^^^^^^^^^ + +.. deprecated:: 13.0.0 + +``ImageQt.align8to32()`` has been deprecated. This was an undocumented helper function +intended for internal use, so there is no replacement. + Removed features ---------------- diff --git a/docs/releasenotes/13.0.0.rst b/docs/releasenotes/13.0.0.rst index d6d0ff6c40e..5ccec3b1e30 100644 --- a/docs/releasenotes/13.0.0.rst +++ b/docs/releasenotes/13.0.0.rst @@ -69,10 +69,11 @@ ImageCms.ImageCmsProfile.product_name and .product_info Deprecations ============ -TODO -^^^^ +ImageQt align8to32() +^^^^^^^^^^^^^^^^^^^^ -TODO +``ImageQt.align8to32()`` has been deprecated. This was an undocumented helper function +intended for internal use, so there is no replacement. API changes =========== diff --git a/src/PIL/ImageQt.py b/src/PIL/ImageQt.py index 746e66e8aee..5f4c7016424 100644 --- a/src/PIL/ImageQt.py +++ b/src/PIL/ImageQt.py @@ -108,9 +108,7 @@ def align8to32(bytes: bytes, width: int, mode: str) -> bytes: """ converts each scanline of data from 8 bit to 32 bit aligned """ - deprecate( - "ImageQt.align8to32", 14, action="Implement a similar function in your code" - ) + deprecate("ImageQt.align8to32", 14) bits_per_pixel = {"1": 1, "L": 8, "P": 8, "I;16": 16}[mode] From c4c2045a3e253ded503940cd98653c73d141ad60 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Thu, 3 Sep 2026 18:33:00 +1000 Subject: [PATCH 3/4] Inline function --- Tests/test_imageqt.py | 9 ++------- src/PIL/ImageQt.py | 14 ++++++-------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/Tests/test_imageqt.py b/Tests/test_imageqt.py index d139b59bf5d..e9c16cf2f69 100644 --- a/Tests/test_imageqt.py +++ b/Tests/test_imageqt.py @@ -56,11 +56,6 @@ def test_closed_file() -> None: def test_deprecated_align8to32_matches_new_impl() -> None: - im = hopper("P").resize((113, 113)) # size causes alignment issues - w, h = im.size + im = hopper("1") with pytest.warns(DeprecationWarning, match="ImageQt.align8to32"): - old_b = ImageQt.align8to32(im.tobytes(), w, im.mode) - stride = ImageQt._aligned_stride(w, im.mode) - new_b = im.tobytes("raw", im.mode, stride) - assert old_b == new_b - assert len(old_b) == stride * h + ImageQt.align8to32(im.tobytes(), im.width, im.mode) diff --git a/src/PIL/ImageQt.py b/src/PIL/ImageQt.py index 5f4c7016424..c5d09f00d84 100644 --- a/src/PIL/ImageQt.py +++ b/src/PIL/ImageQt.py @@ -131,13 +131,6 @@ def align8to32(bytes: bytes, width: int, mode: str) -> bytes: return b"".join(new_data) -def _aligned_stride(width: int, mode: str) -> int: - # Compute the stride (scanline size) in bytes when aligned - # to Qt's requirement that scanlines be aligned to 32 bits. - mode_bpp = {"1": 1, "L": 8, "P": 8, "I;16": 16} - return (mode_bpp[mode] * width + 31) // 32 * (32 // 8) - - def _toqclass_helper(im: Image.Image | str | QByteArray) -> dict[str, Any]: data = None colortable = None @@ -184,7 +177,12 @@ def _toqclass_helper(im: Image.Image | str | QByteArray) -> dict[str, Any]: size = im.size if data is None: - data = im.tobytes("raw", im.mode, _aligned_stride(size[0], im.mode)) + # Compute the stride (scanline size) in bytes when aligned + # to Qt's requirement that scanlines be aligned to 32 bits. + bpp = {"1": 1, "L": 8, "P": 8, "I;16": 16}[im.mode] + stride = (bpp * size[0] + 31) // 32 * (32 // 8) + + data = im.tobytes("raw", im.mode, stride) if exclusive_fp: im.close() return {"data": data, "size": size, "format": format, "colortable": colortable} From 5f8595db3c0567c34679f9cd48af6c02e61cb901 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 4 Sep 2026 15:46:51 +1000 Subject: [PATCH 4/4] Update test name --- Tests/test_imageqt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/test_imageqt.py b/Tests/test_imageqt.py index e9c16cf2f69..c7a73d41b33 100644 --- a/Tests/test_imageqt.py +++ b/Tests/test_imageqt.py @@ -55,7 +55,7 @@ def test_closed_file() -> None: ImageQt.ImageQt("Tests/images/hopper.gif") -def test_deprecated_align8to32_matches_new_impl() -> None: +def test_align8to32_deprecation() -> None: im = hopper("1") with pytest.warns(DeprecationWarning, match="ImageQt.align8to32"): ImageQt.align8to32(im.tobytes(), im.width, im.mode)