diff --git a/Tests/test_imageops.py b/Tests/test_imageops.py index c7e63fbe548..4a4826d22e3 100644 --- a/Tests/test_imageops.py +++ b/Tests/test_imageops.py @@ -232,6 +232,23 @@ def test_rgba_palette() -> None: assert expanded_im.convert("RGBA").getpixel((0, 0)) == translucent_black +def test_transparency() -> None: + im = Image.new("P", (1, 1)) + im.info["transparency"] = 0 + + expanded_im = ImageOps.expand(im, 1, "blue") + assert expanded_im.info["transparency"] == 0 + expanded_im_rgba = expanded_im.convert("RGBA") + assert expanded_im_rgba.getpixel((0, 0)) == (0, 0, 255, 255) + assert expanded_im_rgba.getpixel((1, 1)) == (0, 0, 0, 0) + + padded_im = ImageOps.pad(im, (3, 1), color="blue") + assert padded_im.info["transparency"] == 0 + padded_im_rgba = padded_im.convert("RGBA") + assert padded_im_rgba.getpixel((0, 0)) == (0, 0, 255, 255) + assert padded_im_rgba.getpixel((1, 0)) == (0, 0, 0, 0) + + def test_pil163() -> None: # Division by zero in equalize if < 255 pixels in image (@PIL163) diff --git a/docs/releasenotes/13.0.0.rst b/docs/releasenotes/13.0.0.rst index 520d972cd88..74603803e46 100644 --- a/docs/releasenotes/13.0.0.rst +++ b/docs/releasenotes/13.0.0.rst @@ -135,6 +135,14 @@ immediately at the release of 3.15.0 final (2026-10-01, :pep:`790`). Pillow 13.0.0 now officially supports Python 3.15. +Preserved transparency when padding or expanding images in ImageOps +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:py:func:`~PIL.ImageOps.pad` and :py:func:`~PIL.ImageOps.expand` now preserve the +``transparency`` value from the source image's ``info`` dictionary. Transparent +pixels in L, P and RGB images previously became opaque when a border was added. +New palette colors are allocated without using reserved transparency entries. + Restore image position if ImageSequence.all_frames() fails ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/PIL/ImageOps.py b/src/PIL/ImageOps.py index 94964e12156..593f801b031 100644 --- a/src/PIL/ImageOps.py +++ b/src/PIL/ImageOps.py @@ -349,12 +349,14 @@ def _new_with_fill( mode = image.palette.mode palette = ImagePalette.ImagePalette(mode, image.getpalette(mode)) if isinstance(color, tuple) and len(color) in (3, 4): - color = palette.getcolor(color) + color = palette.getcolor(color, image) else: palette = None out = Image.new(image.mode, size, color) if palette: out.putpalette(palette.palette, mode) + if "transparency" in image.info: + out.info["transparency"] = image.info["transparency"] return out