Deprecate saving I mode images as PNG (#9023)

This commit is contained in:
Hugo van Kemenade 2025-06-21 11:24:28 +01:00 committed by GitHub
commit 13faa4681c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 41 additions and 6 deletions

View File

@ -100,11 +100,11 @@ class TestFilePng:
assert im.format == "PNG"
assert im.get_format_mimetype() == "image/png"
for mode in ["1", "L", "P", "RGB", "I", "I;16", "I;16B"]:
for mode in ["1", "L", "P", "RGB", "I;16", "I;16B"]:
im = hopper(mode)
im.save(test_file)
with Image.open(test_file) as reloaded:
if mode in ("I", "I;16B"):
if mode == "I;16B":
reloaded = reloaded.convert(mode)
assert_image_equal(reloaded, im)
@ -801,6 +801,16 @@ class TestFilePng:
with Image.open("Tests/images/truncated_end_chunk.png") as im:
assert_image_equal_tofile(im, "Tests/images/hopper.png")
def test_deprecation(self, tmp_path: Path) -> None:
test_file = tmp_path / "out.png"
im = hopper("I")
with pytest.warns(DeprecationWarning):
im.save(test_file)
with Image.open(test_file) as reloaded:
assert_image_equal(im, reloaded.convert("I"))
@pytest.mark.skipif(is_win32(), reason="Requires Unix or macOS")
@skip_unless_feature("zlib")

View File

@ -193,6 +193,20 @@ Image.Image.get_child_images()
method uses an image's file pointer, and so child images could only be retrieved from
an :py:class:`PIL.ImageFile.ImageFile` instance.
Saving I mode images as PNG
^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. deprecated:: 11.3.0
In order to fit the 32 bits of I mode images into PNG, when PNG images can only contain
at most 16 bits for a channel, Pillow has been clipping the values. Rather than quietly
changing the data, this is now deprecated. Instead, the image can be converted to
another mode before saving::
from PIL import Image
im = Image.new("I", (1, 1))
im.convert("I;16").save("out.png")
Removed features
----------------

View File

@ -23,10 +23,17 @@ TODO
Deprecations
============
TODO
^^^^
Saving I mode images as PNG
^^^^^^^^^^^^^^^^^^^^^^^^^^^
TODO
In order to fit the 32 bits of I mode images into PNG, when PNG images can only contain
at most 16 bits for a channel, Pillow has been clipping the values. Rather than quietly
changing the data, this is now deprecated. Instead, the image can be converted to
another mode before saving::
from PIL import Image
im = Image.new("I", (1, 1))
im.convert("I;16").save("out.png")
API changes
===========

View File

@ -48,6 +48,7 @@ from ._binary import i32be as i32
from ._binary import o8
from ._binary import o16be as o16
from ._binary import o32be as o32
from ._deprecate import deprecate
from ._util import DeferredError
TYPE_CHECKING = False
@ -1368,6 +1369,8 @@ def _save(
except KeyError as e:
msg = f"cannot write mode {mode} as PNG"
raise OSError(msg) from e
if outmode == "I":
deprecate("Saving I mode images as PNG", 13, stacklevel=4)
#
# write minimal PNG file

View File

@ -12,6 +12,7 @@ def deprecate(
*,
action: str | None = None,
plural: bool = False,
stacklevel: int = 3,
) -> None:
"""
Deprecations helper.
@ -67,5 +68,5 @@ def deprecate(
warnings.warn(
f"{deprecated} {is_} deprecated and will be removed in {removed}{action}",
DeprecationWarning,
stacklevel=3,
stacklevel=stacklevel,
)