首页 > 解决方案 > 如何使用 PIL 在半透明背景上创建重叠的半透明形状

问题描述

我正在尝试创建在透明背景上绘制的半透明形状的图像。由于某种原因,这些形状并没有保持透明,而是完全覆盖了它们下面的形状。我的代码:

from PIL import Image, ImageDraw
img = Image.new("RGBA", (256, 256), (255,0,0,127))
drawing = ImageDraw.Draw(img, "RGBA")
drawing.ellipse((127-79, 127 - 63, 127 + 47, 127 + 63), fill=(0, 255, 0, 63), outline=(0, 255, 0, 255))
drawing.ellipse((127-47, 127 - 63, 127 + 79, 127 + 63), fill=(0, 0, 255, 63), outline=(0, 0, 255, 255))
img.save("foo.png", "png")

我希望结果看起来像(除了背景不透明):
预期的
但它看起来像:
实际的

当我尝试将其保存为 GIF 时img.save("foo.gif", "gif"),结果更糟。圆圈是实心的,轮廓和填充之间没有区别。

标签: pythonpython-imaging-library

解决方案


正如我在评论中提到的,ImageDraw.Draw不进行混合——无论绘制什么都会替换之前存在的任何像素。要获得您想要的效果,需要分两步进行绘制。椭圆必须首先在空白透明背景上绘制,然后必须与当前图像 ( ) 进行alpha 合成bg_img以保持透明度。

在下面的代码中,这已在可重用功能中实现:

from PIL import Image, ImageDraw


def draw_transp_ellipse(img, xy, **kwargs):
    """ Draws an ellipse inside the given bounding box onto given image.
        Supports transparent colors
    """
    transp = Image.new('RGBA', img.size, (0,0,0,0))  # Temp drawing image.
    draw = ImageDraw.Draw(transp, "RGBA")
    draw.ellipse(xy, **kwargs)
    # Alpha composite two images together and replace first with result.
    img.paste(Image.alpha_composite(img, transp))


bg_img = Image.new("RGBA", (256, 256), (255, 0, 0, 127))  # Semitransparent background.

draw_transp_ellipse(bg_img, (127-79, 127-63, 127+47, 127+63),
                    fill=(0, 255, 0, 63), outline=(0, 255, 0, 255))
draw_transp_ellipse(bg_img, (127-47, 127-63, 127+79, 127+63),
                    fill=(0, 0, 255, 63), outline=(0, 0, 255, 255))

bg_img.save("foo.png")

这是它在我的图像文件编辑器应用程序中创建的图像,它使用棋盘图案呈现图像的半透明部分。正如您所看到的,不透明的轮廓是唯一不是的部分。

图片编辑器中的图片截图


推荐阅读