Skip to content

Commit

Permalink
Merge pull request #7420 from radarhere/transparency
Browse files Browse the repository at this point in the history
  • Loading branch information
hugovk committed Sep 30, 2023
2 parents 29ae275 + 4142fc4 commit 8cb1e29
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 10 deletions.
10 changes: 10 additions & 0 deletions Tests/test_file_webp.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,13 @@ def test_duration(self, tmp_path):
with Image.open(out_webp) as reloaded:
reloaded.load()
assert reloaded.info["duration"] == 1000

def test_roundtrip_rgba_palette(self, tmp_path):
temp_file = str(tmp_path / "temp.webp")
im = Image.new("RGBA", (1, 1)).convert("P")
assert im.mode == "P"
assert im.palette.mode == "RGBA"
im.save(temp_file)

with Image.open(temp_file) as im:
assert im.getpixel((0, 0)) == (0, 0, 0, 0)
25 changes: 25 additions & 0 deletions Tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,31 @@ def test_zero_tobytes(self, size):
im = Image.new("RGB", size)
assert im.tobytes() == b""

def test_has_transparency_data(self):
for mode in ("1", "L", "P", "RGB"):
im = Image.new(mode, (1, 1))
assert not im.has_transparency_data

for mode in ("LA", "La", "PA", "RGBA", "RGBa"):
im = Image.new(mode, (1, 1))
assert im.has_transparency_data

# P mode with "transparency" info
with Image.open("Tests/images/first_frame_transparency.gif") as im:
assert "transparency" in im.info
assert im.has_transparency_data

# RGB mode with "transparency" info
with Image.open("Tests/images/rgb_trns.png") as im:
assert "transparency" in im.info
assert im.has_transparency_data

# P mode with RGBA palette
im = Image.new("RGBA", (1, 1)).convert("P")
assert im.mode == "P"
assert im.palette.mode == "RGBA"
assert im.has_transparency_data

def test_apply_transparency(self):
im = Image.new("P", (1, 1))
im.putpalette((0, 0, 0, 1, 1, 1))
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/Image.rst
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,8 @@ Instances of the :py:class:`Image` class have the following attributes:

.. seealso:: :attr:`~Image.is_animated`, :func:`~Image.seek` and :func:`~Image.tell`

.. autoattribute:: PIL.Image.Image.has_transparency_data

Classes
-------

Expand Down
12 changes: 9 additions & 3 deletions docs/releasenotes/10.1.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,16 @@ TODO
API Additions
=============

TODO
^^^^
has_transparency_data
^^^^^^^^^^^^^^^^^^^^^

TODO
Images now have :py:attr:`~PIL.Image.Image.has_transparency_data` to indicate
whether the image has transparency data, whether in the form of an alpha
channel, a palette with an alpha channel, or a "transparency" key in the
:py:attr:`~PIL.Image.Image.info` dictionary.

Even if this attribute is true, the image might still appear solid, if all of
the values shown within are opaque.

Security
========
Expand Down
20 changes: 19 additions & 1 deletion src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,7 @@ def convert(

self.load()

has_transparency = self.info.get("transparency") is not None
has_transparency = "transparency" in self.info
if not mode and self.mode == "P":
# determine default mode
if self.palette:
Expand Down Expand Up @@ -1531,6 +1531,24 @@ def getpalette(self, rawmode="RGB"):
rawmode = mode
return list(self.im.getpalette(mode, rawmode))

@property
def has_transparency_data(self) -> bool:
"""
Determine if an image has transparency data, whether in the form of an
alpha channel, a palette with an alpha channel, or a "transparency" key
in the info dictionary.
Note the image might still appear solid, if all of the values shown
within are opaque.
:returns: A boolean.
"""
return (
self.mode in ("LA", "La", "PA", "RGBA", "RGBa")
or (self.mode == "P" and self.palette.mode.endswith("A"))
or "transparency" in self.info
)

def apply_transparency(self):
"""
If a P mode image has a "transparency" key in the info dictionary,
Expand Down
7 changes: 1 addition & 6 deletions src/PIL/WebPImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,12 +330,7 @@ def _save(im, fp, filename):
exact = 1 if im.encoderinfo.get("exact") else 0

if im.mode not in _VALID_WEBP_LEGACY_MODES:
alpha = (
"A" in im.mode
or "a" in im.mode
or (im.mode == "P" and "transparency" in im.info)
)
im = im.convert("RGBA" if alpha else "RGB")
im = im.convert("RGBA" if im.has_transparency_data else "RGB")

data = _webp.WebPEncode(
im.tobytes(),
Expand Down

0 comments on commit 8cb1e29

Please sign in to comment.