开发者

How to merge a transparent png image with another image using PIL

I have a transparent png image foo.png and I've opened 开发者_开发百科another image with:

im = Image.open("foo2.png")

Now what I need is to merge foo.png with foo2.png.

(foo.png contains some text and I want to print that text on foo2.png)


from PIL import Image

background = Image.open("test1.png")
foreground = Image.open("test2.png")

background.paste(foreground, (0, 0), foreground)
background.show()

First parameter to .paste() is the image to paste. Second are coordinates, and the secret sauce is the third parameter. It indicates a mask that will be used to paste the image. If you pass a image with transparency, then the alpha channel is used as mask.

Check the docs.


Image.paste does not work as expected when the background image also contains transparency. You need to use real Alpha Compositing.

Pillow 2.0 contains an alpha_composite function that does this.

background = Image.open("test1.png")
foreground = Image.open("test2.png")

Image.alpha_composite(background, foreground).save("test3.png")

EDIT: Both images need to be of the type RGBA. So you need to call convert('RGBA') if they are paletted, etc.. If the background does not have an alpha channel, then you can use the regular paste method (which should be faster).


As olt already pointed out, Image.paste doesn't work properly, when source and destination both contain alpha.

Consider the following scenario:

Two test images, both contain alpha:

How to merge a transparent png image with another image using PIL

How to merge a transparent png image with another image using PIL

layer1 = Image.open("layer1.png")
layer2 = Image.open("layer2.png")

Compositing image using Image.paste like so:

final1 = Image.new("RGBA", layer1.size)
final1.paste(layer1, (0,0), layer1)
final1.paste(layer2, (0,0), layer2)

produces the following image (the alpha part of the overlayed red pixels is completely taken from the 2nd layer. The pixels are not blended correctly):

How to merge a transparent png image with another image using PIL

Compositing image using Image.alpha_composite like so:

final2 = Image.new("RGBA", layer1.size)
final2 = Image.alpha_composite(final2, layer1)
final2 = Image.alpha_composite(final2, layer2)

produces the following (correct) image:

How to merge a transparent png image with another image using PIL


One can also use blending:

im1 = Image.open("im1.png")
im2 = Image.open("im2.png")
blended = Image.blend(im1, im2, alpha=0.5)
blended.save("blended.png")


Had a similar question and had difficulty finding an answer. The following function allows you to paste an image with a transparency parameter over another image at a specific offset.

import Image

def trans_paste(fg_img,bg_img,alpha=1.0,box=(0,0)):
    fg_img_trans = Image.new("RGBA",fg_img.size)
    fg_img_trans = Image.blend(fg_img_trans,fg_img,alpha)
    bg_img.paste(fg_img_trans,box,fg_img_trans)
    return bg_img

bg_img = Image.open("bg.png")
fg_img = Image.open("fg.png")
p = trans_paste(fg_img,bg_img,.7,(250,100))
p.show()


def trans_paste(bg_img,fg_img,box=(0,0)):
    fg_img_trans = Image.new("RGBA",bg_img.size)
    fg_img_trans.paste(fg_img,box,mask=fg_img)
    new_img = Image.alpha_composite(bg_img,fg_img_trans)
    return new_img


Here is my code to merge 2 images of different sizes, each with transparency and with offset:

from PIL import Image

background = Image.open('image1.png')
foreground = Image.open("image2.png")

x = background.size[0]//2
y = background.size[1]//2

background = Image.alpha_composite(
    Image.new("RGBA", background.size),
    background.convert('RGBA')
)

background.paste(
    foreground,
    (x, y),
    foreground
)

background.show()

This snippet is a mix of the previous answers, blending elements with offset while handling images with different sizes, each with transparency.


the key code is:

_, _, _, alpha = image_element_copy.split()
image_bg_copy.paste(image_element_copy, box=(x0, y0, x1, y1), mask=alpha)

the full function is:

def paste_image(image_bg, image_element, cx, cy, w, h, rotate=0, h_flip=False):
    image_bg_copy = image_bg.copy()
    image_element_copy = image_element.copy()

    image_element_copy = image_element_copy.resize(size=(w, h))
    if h_flip:
        image_element_copy = image_element_copy.transpose(Image.FLIP_LEFT_RIGHT)
    image_element_copy = image_element_copy.rotate(rotate, expand=True)
    _, _, _, alpha = image_element_copy.split()
    # image_element_copy's width and height will change after rotation
    w = image_element_copy.width
    h = image_element_copy.height
    x0 = cx - w // 2
    y0 = cy - h // 2
    x1 = x0 + w
    y1 = y0 + h
    image_bg_copy.paste(image_element_copy, box=(x0, y0, x1, y1), mask=alpha)
    return image_bg_copy

the above function supports:

  • position(cx, cy)
  • auto resize image_element to (w, h)
  • rotate image_element without cropping it
  • horizontal flip
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜