Are RGBA PNGs unsupported in Python 3.5 + Pillow? Are RGBA PNGs unsupported in Python 3.5 + Pillow? tkinter tkinter

Are RGBA PNGs unsupported in Python 3.5 + Pillow?


Woot! I solved this.

TL;DR - YES RGBA* PNGS are unsupported in Pillow/Tkinker - but a work around is below and force the Alpha channel to have values only 0 or 255

*A channel cannot have any values other than 0 or 255, if it does then the whole image is not drawn (even the pixels with 255 in the alpha channel.)

Longer version:It was bugging the crap out of me. Turns out my issue is that photoshop saves out the Alpha channel with 8 bits of information and so my test images had subtle transparencies in ranges that I could not see by eye. They looked either opaque or transparent when I viewed the images.

But by comparing what the actual bytes where after the successful case of the rectangle transparency test case I could see that Image only wants 0 for transparent or 255 for opaque (As Tkinter is dynamically laying out the GUI it doesn't know what the color is of the pixel below to blend in the case of partial transparency.)

So, to fix this, I now run my images through this helper function I created below that flips the 8 bits of information coming in on the alpha channel and forces them to be either 0 or 255. I chose somewhat arbitrarily that in the case of 50 and below I would consider it transparent.

Hopefully someone else sees this before having to figure this out from scratch.

# Fixes the issue when trying to render RBGAs that have 8bits of information in the alpha channel# Turns your image into 8 bits on RGB and then 1 bit on the A channel# This will render correctly# See the example below for how to usefrom PIL import Imagedef flattenAlpha(img):    alpha = img.split()[-1]  # Pull off the alpha layer    ab = alpha.tobytes()  # Original 8-bit alpha    checked = []  # Create a new array to store the cleaned up alpha layer bytes    # Walk through all pixels and set them either to 0 for transparent or 255 for opaque fancy pants    transparent = 50  # change to suit your tolerance for what is and is not transparent    p = 0    for pixel in range(0, len(ab)):        if ab[pixel] < transparent:            checked.append(0)  # Transparent        else:            checked.append(255)  # Opaque        p += 1    mask = Image.frombytes('L', img.size, bytes(checked))    img.putalpha(mask)    return img# Run this as a test case.# Assumes that you have a PNG named "CuriosityRover.png"# that is an RGBA with varying levels of Alpha in the# subdirectory assets from your working directoryif __name__ == "__main__":    from PIL import ImageTk    import tkinter as tk    img = Image.open("./Assets/CuriosityRover.png")    img = flattenAlpha(img)    root = tk.Tk()    photo = ImageTk.PhotoImage(img)    canvas = tk.Canvas(root, width=600, height=600, bg="red")    canvas.create_image((300, 300), image=photo)    canvas.grid(row=0, column=0)    root.mainloop()