Python PIL - 所有透明度大于0的PNG区域都被设置为1

4 投票
2 回答
2401 浏览
提问于 2025-04-16 07:17

想象一下,有一个红色的圆圈,上面有一个黑色的阴影,这个阴影在完全透明的背景上逐渐消失。当我用PIL打开并重新保存这个图片时,背景依然是完全透明的,但阴影却变成了纯黑色。

这个问题出现的时候,我甚至没有对图片进行任何修改:

image = Image.open('input.png')
image = image.convert('RGBA')
image.save('output.png')

我希望图片看起来和原来一模一样,这样我才能裁剪或调整它的大小。

补充说明:这里有一个PNG图片,展示了这个效果。它是通过使用PNGNQ转换成8位的。

alt text

使用上面的Python代码处理后,结果变成了这样:

alt text

2 个回答

0

我觉得这个问题已经有点解决了,不过你有没有想过可能需要设置一下透明通道的深度呢?

6

看起来PIL目前不支持PNG8格式的完整透明度。

这里有一个补丁,可以实现只读支持:http://mail.python.org/pipermail/image-sig/2010-October/006533.html

如果你想尝试一些不太正规的做法,可以对PIL进行修改:

from PIL import Image, ImageFile, PngImagePlugin

def patched_chunk_tRNS(self, pos, len):
    i16 = PngImagePlugin.i16
    s = ImageFile._safe_read(self.fp, len)
    if self.im_mode == "P":
        self.im_info["transparency"] = map(ord, s)
    elif self.im_mode == "L":
        self.im_info["transparency"] = i16(s)
    elif self.im_mode == "RGB":
        self.im_info["transparency"] = i16(s), i16(s[2:]), i16(s[4:])
    return s
PngImagePlugin.PngStream.chunk_tRNS = patched_chunk_tRNS

def patched_load(self):
    if self.im and self.palette and self.palette.dirty:
        apply(self.im.putpalette, self.palette.getdata())
        self.palette.dirty = 0
        self.palette.rawmode = None
        try:
            trans = self.info["transparency"]
        except KeyError:
            self.palette.mode = "RGB"
        else:
            try:
                for i, a in enumerate(trans):
                    self.im.putpalettealpha(i, a)
            except TypeError:
                self.im.putpalettealpha(trans, 0)
            self.palette.mode = "RGBA"
    if self.im:
        return self.im.pixel_access(self.readonly)
Image.Image.load = patched_load

Image.open('kHrY6.png').convert('RGBA').save('kHrY6-out.png')

撰写回答