Preserve transparency when padding and expanding images - #9995
lllleolin-max wants to merge 2 commits into
Conversation
|
|
||
| :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 P, L and RGB images previously became opaque when a border was added. |
There was a problem hiding this comment.
| pixels in P, L and RGB images previously became opaque when a border was added. | |
| pixels in L, P and RGB images previously became opaque when a border was added. |
Nitpick suggestion. I would rather list the modes in increasing order of complexity.
| ) -> None: | ||
| im = Image.new("P", (1, 1)) | ||
| im.putpalette([0, 0, 0]) | ||
| im.info["transparency"] = transparency |
There was a problem hiding this comment.
I believe the use of bytes in im.info["transparency"] is limited to the PNG format, with its tRNS chunk. If there are other formats you're aware of, let me know.
You are testing an image here with 1 palette entry ([0, 0, 0]), but two transparency bytes (b"\xff\x00"). That would make for an invalid PNG.
https://www.libpng.org/pub/png/spec/1.2/PNG-Chunks.html#C.tRNS
The tRNS chunk must not contain more alpha values than there are palette entries
From this, I conclude that your changes to ImagePalette are not needed.
|
Thank you for catching this. You're right that the one-entry palette with two transparency bytes does not represent a valid PNG input. I overlooked that constraint, and this fixture should not have been used to justify the allocation change. I rechecked the original issue using valid PNGs saved and reopened before the operation. With a two-entry palette (black and red) and transparency index 0, Would you prefer that I remove the ImagePalette changes and the out-of-range fixtures, and keep this PR focused on preserving transparency in ImageOps? I can leave full-palette allocation behavior for a separate discussion. Sorry for overlooking the invalid fixture, and thank you for the careful review. |
ImageOps.pad()andImageOps.expand()discardinfo["transparency"]when creating an image with a border. Transparent pixels consequently become opaque in P, L and RGB images, including when the result is saved as PNG.Changes proposed in this pull request:
_new_with_fill()helper and pass the source image when allocating a new palette color, so reserved transparency indices are not reused for the border.Reproduction:
Validation:
main: 15 failed, 90 passed. Twelve failures show the output pixels losing transparency; three cover allocation into transparent palette entries.Tests/test_imageops.py,Tests/test_imagepalette.py,Tests/test_imagecolor.pyandTests/test_imagestat.py: 105 passed, no skips. The existingTests/test_imagedraw.py::test_new_coloralso passes;selftest.py: 59 passed.Tests ran on Windows/Python 3.12.11 using the checkout's
ImageOps,ImagePalette,ImageColorandImageStatPython modules with Pillow 12.3.0's prebuilt native extensions and remaining Python modules. Native extensions were not rebuilt; the full test suite and full pre-commit suite were not run.Prepared with AI assistance.
CI follow-up (2026-09-14): The Windows Python 3.13 and 3.14 x64 checks passed on the maintainer-triggered second attempt of run 34751277259, on the unchanged commit 2d53304. All 53 reported checks passed before the release-note follow-up. The earlier PNG decoding worker crashes have not been root-caused; a successful rerun does not establish that the underlying cause has been fixed. No source or tests were changed to suppress those failures. On the documentation-only follow-up de0892e, Windows Python 3.14 failed again in the same two RGB round-trip tests (2 failed, 4107 passed), while Python 3.13 passed. The failure remains unresolved; this PR remains in draft.
CI comparison (2026-09-14): The passing Windows 3.14 rerun and the subsequent failure both used Python 3.14.7, Windows image
20260907.229.1, zlib-ng 2.3.3, pytest 9.1.1, pytest-cov 7.1.0 and pytest-xdist 3.8.0 with four workers. Their actual checked-out merge commits,f15c554e3d80b79288707cb6dc0e7051f4af45b6and8c12e4c14b7121d5f34b17d413c2fd3bf1a73729, have identical top-level Git tree entries exceptdocs, including identical source, tests, build and CI configuration. Both also checked out cached dependencies at0a1e459d4dbd36ef4f6b411124441f96bdef1110. Static review found the PNG save/seek/open sequence and buffer lifetime consistent with the existing PNG tests. This narrows the comparison but does not identify the crash cause; no tests or dependencies have been changed to suppress it.