Skip to content

Method to test if image has transparency/alpha #7384

@chinery

Description

@chinery

[2023/09/11 edit] adding a tl;dr:

  1. Online sources do not agree on a single method to check for either transparency (actual transparent pixels) or the presence of an alpha channel (whether or not it is opaque), and for all the examples I've found, it's easy to craft examples on which they fail. It would be useful to have an authoritative correct solution from someone who really understands Pillow/images that handles all the edge cases. Or in lieu of that, we could crowd-source one here.
  2. Given the frequency of the question and the widespread incorrect code, it seems like it'd be useful to add this feature to Pillow itself.

Original post:

I found myself wanting to check if an image had an alpha channel/transparency (I'm allowing for a distinction between those, perhaps there isn't a meaningful one). I was trying to convert some optimised images that didn't contain any transparency, so wanted to do something different in that case.

Checking for this is slightly tricky though, and I've seen incorrect logic posted elsewhere, e.g. this stackoverflow post references this stackoverflow post which states to use:

img.mode in ('RGBA', 'LA') or (img.mode == 'P' and 'transparency' in img.info)

But palette-mode images can store their transparency in at least two ways, in img.info, or the palette itself might be RGBA. If you run the following

img = Image.new("RGBA", (100, 100), (128, 128, 128, 128)).quantize()
print(img.mode in ('RGBA', 'LA') or (img.mode == 'P' and 'transparency' in img.info)) # False

the result is False, but clearly it has alpha values in the palette:

print(img.palette.mode) # 'RGBA'
print(img.palette.colors) # {(128, 128, 128, 128): 0, (0, 0, 0, 0): 1}

Would it be possible to add something like img.has_alpha() or img.has_transparency() to help here?

I'm not familiar enough with Pillow's image formats to say whether checking the mode of the palette in addition to the checks above would be exhaustive. Perhaps someone can clarify? Is it sufficient to check img.palette.mode == 'RGBA'? .quantize() does not seem to like an LA image, but if I manually set the palette mode and colors, it works with show(). Then there are other esoteric modes with alpha channels. So perhaps something like this will work?

alpha_modes = {"RGBA", "RGBa", "LA", "La", "PA"}
return img.mode in alpha_modes or (
    img.mode == "P"
    and ("transparency" in img.info or img.palette.mode in alpha_modes)
)

but I very easily could have missed something due to inexperience with the unusual image formats.

(Happy to have a go at the implementation if that would be of assistance!)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions