【问题标题】:How to create overlapping semitransparent shapes on semitransparent background with PIL如何使用 OIL 在半透明背景上创建重叠的半透明形状
【发布时间】:2019-01-29 15:11:10
【问题描述】:

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

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")

我希望结果看起来像(除了背景不透明):

但看起来像:

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

【问题讨论】:

  • ImageDraw.Draw 不进行混合,它用新像素替换像素。做你想做的事需要两个步骤——在空白画布上不透明地绘制,然后合成结果。有一个example in the documentation 绘制部分不透明的文本。我对相关问题的answer 有另一个例子。

标签: python python-imaging-library


【解决方案1】:

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

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

【讨论】:

  • 太好了,这行得通。不过,我会等待其他答案一段时间,因为我怀疑应该有一些更简单的方法。 ImageDraw.Draw 可以在使用Image.new('RGB',... 时进行混合。
  • Alex:当然,没问题。我理解你的怀疑,但不认为是这种情况——但如果我自己发现有更好的方法,我会很惊喜。在我看来,这种方法似乎是真正的kludge,而且效率很低。您可能已经注意到,ImageDraw 仅具有原始绘图功能,甚至无法绘制抗锯齿线或椭圆。
  • @martineau 非常感谢!在尝试了很多东西之后,包括blend,终于成功了!
【解决方案2】:

所有第 4 维 - 透明度必须为一半。也可能是绘图的问题。为每个椭圆制作蒙版,然后总结图像。最后一个选项 - 检查弯曲图像的 pil 功能。这可能是最确定和最简单的解决方案。

混合的功能是:

PIL.Image. blend (im1, im2, alpha)

【讨论】:

  • 您能详细说明一下吗?我刚刚试了一下,结果并没有太大的不同。
猜你喜欢
  • 2018-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-15
  • 2015-11-12
  • 2014-08-20
  • 1970-01-01
相关资源
最近更新 更多