Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added apply_transparency() #6352

Merged
merged 2 commits into from Jun 11, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
29 changes: 29 additions & 0 deletions Tests/test_image.py
Expand Up @@ -840,6 +840,35 @@ def test_zero_tobytes(self, size):
im = Image.new("RGB", size)
assert im.tobytes() == b""

def test_apply_transparency(self):
im = Image.new("P", (1, 1))
im.putpalette((0, 0, 0, 1, 1, 1))
assert im.palette.colors == {(0, 0, 0): 0, (1, 1, 1): 1}

# Test that no transformation is applied without transparency
im.apply_transparency()
assert im.palette.colors == {(0, 0, 0): 0, (1, 1, 1): 1}

# Test that a transparency index is applied
im.info["transparency"] = 0
im.apply_transparency()
assert "transparency" not in im.info
assert im.palette.colors == {(0, 0, 0, 0): 0, (1, 1, 1, 255): 1}

# Test that existing transparency is kept
im = Image.new("P", (1, 1))
im.putpalette((0, 0, 0, 255, 1, 1, 1, 128), "RGBA")
im.info["transparency"] = 0
im.apply_transparency()
assert im.palette.colors == {(0, 0, 0, 0): 0, (1, 1, 1, 128): 1}

# Test that transparency bytes are applied
with Image.open("Tests/images/pil123p.png") as im:
assert isinstance(im.info["transparency"], bytes)
assert im.palette.colors[(27, 35, 6)] == 24
im.apply_transparency()
assert im.palette.colors[(27, 35, 6, 214)] == 24

def test_categories_deprecation(self):
with pytest.warns(DeprecationWarning):
assert hopper().category == 0
Expand Down
1 change: 1 addition & 0 deletions docs/reference/Image.rst
Expand Up @@ -123,6 +123,7 @@ methods. Unless otherwise stated, all methods return a new instance of the


.. automethod:: PIL.Image.Image.alpha_composite
.. automethod:: PIL.Image.Image.apply_transparency
.. automethod:: PIL.Image.Image.convert

The following example converts an RGB image (linearly calibrated according to
Expand Down
9 changes: 6 additions & 3 deletions docs/releasenotes/9.2.0.rst
Expand Up @@ -57,10 +57,13 @@ TODO
API Additions
=============

TODO
^^^^
Image.apply_transparency
^^^^^^^^^^^^^^^^^^^^^^^^

TODO
Added :py:meth:`~PIL.Image.Image.apply_transparency`, a method to take a P mode image
with "transparency" in ``im.info``, and apply the transparency to the palette instead.
The image's palette mode will become "RGBA", and "transparency" will be removed from
``im.info``.

Security
========
Expand Down
22 changes: 22 additions & 0 deletions src/PIL/Image.py
Expand Up @@ -1449,6 +1449,28 @@ def getpalette(self, rawmode="RGB"):
rawmode = mode
return list(self.im.getpalette(mode, rawmode))

def apply_transparency(self):
"""
If a P mode image has a "transparency" key in the info dictionary,
remove the key and apply the transparency to the palette instead.
"""
if self.mode != "P" or "transparency" not in self.info:
return

from . import ImagePalette

palette = self.getpalette("RGBA")
transparency = self.info["transparency"]
if isinstance(transparency, bytes):
for i, alpha in enumerate(transparency):
palette[i * 4 + 3] = alpha
else:
palette[transparency * 4 + 3] = 0
self.palette = ImagePalette.ImagePalette("RGBA", bytes(palette))
self.palette.dirty = 1

del self.info["transparency"]

def getpixel(self, xy):
"""
Returns the pixel value at a given position.
Expand Down