在Python 3.5 + Pillow中不支持RGBA PNG吗?

Eri*_*hke 2 python png alpha tkinter python-3.x

*编辑* 不,我没有尝试转换.BMP只需加载PNG并在tk画布中渲染(透明位实际上是透明的.)

目标:使用透明度加载PNG文件的内容,并使用Python3在tkinter Canvas中呈现它们(并使用Pillow支持PIL)

问题:当加载为RGBA时,它们无法在画布中呈现.将它们转换为RGB并将渲染,但当然没有透明度.

环境:安装Mac OSX,Python 3.5并验证Pillow处于3.5路径

注意:CuriosityRover.png确实是一个RGBA,打印语句确认,并使用finder进行验证,显示灰色背景和Photoshop保存网页的透明度.

我试过像这样只提取alpha层:

 alpha = img.convert('RGBA').split()[-1]
Run Code Online (Sandbox Code Playgroud)

调用alpha.show()确实向我展示了预览alpha图层,但它无法在画布小部件中呈现.

我还尝试使用ImageOps.invert(alpha)反转alpha图层(在应用反转后通过调用.show()验证,我在预览中看到反向alpha图层.)

我试过像这样创建矩形透明区域:transparent_area =(0,0,300,300)mask = Image.new('L',curosity.size,color = 255)draw = ImageDraw.Draw(mask)draw.rectangle (transparent_area,fill = 0)img.putalpha(mask)

确实工作创造一个透明的矩形区域,所以它看起来像canvas.create_image 做工精细的透明度,但不知何故,我无法创建正确的透明度数据的光象.

我有很多堆栈溢出标签打开了一天的过程我很尴尬,我无法弄清楚这一点.

这似乎是世界上最简单的事情.我究竟做错了什么?

import tkinter as tk
from PIL import Image, ImageTk

img = Image.open("./Assets/CuriosityRover.png")
img2 = Image.open("./Assets/CuriosityRover.png").convert('RGB')

img.show()  # Shows the image just fine in preview
print(img.format, img.size, img.mode)

root = tk.Tk()
photo = ImageTk.PhotoImage(img)  # img fails render, img2 works but no alpha

canvas = tk.Canvas(root, width=600, height=600, bg="black")

canvas.create_image((300, 300), image=photo)
canvas.grid(row=0, column=0)

root.mainloop()
Run Code Online (Sandbox Code Playgroud)

Eri*_*hke 5

活泉!我解决了这个问题

Pillow/Tkinker中不支持 TL; DR - YES RGBA*PNGS - 但是下面的解决办法是强制Alpha通道的值只有0或255

*一个通道不能有0或255以外的任何值,如果是,则不绘制整个图像(即使是alpha通道中有255个像素.)

更长的版本:这是我的废话.事实证明,我的问题是,Photoshop以8位信息保存了Alpha通道,因此我的测试图像在我无法通过眼睛看不到的范围内具有微妙的透明度.当我查看图像时,它们看起来不透明或透明.

但通过比较矩形透明度测试案例成功案例之后的实际字节,我可以看到Image只需要0表示透明,255表示不透明(因为Tkinter动态布局GUI,它不知道颜色是什么下面的像素在部分透明的情况下混合.)

因此,为了解决这个问题,我现在通过我在下面创建的辅助函数运行我的图像,它翻转了alpha通道上的8位信息,并强制它们为0或255.我选择了一些任意的,在50以下我认为它是透明的.

希望其他人在看到这一点之前先看清楚这一点.

# 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 use

from PIL import Image


def 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 directory

if __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()
Run Code Online (Sandbox Code Playgroud)