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

177,879

Solution 1

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.

Solution 2

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

Solution 3

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:

enter image description here enter image description here

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

enter image description here

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:

enter image description here

Solution 4

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

Solution 5

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
Share:
177,879

Related videos on Youtube

Arackna
Author by

Arackna

...(00| ... Fr33 4s in Fr33d0m !!

Updated on September 25, 2021

Comments

  • Arackna
    Arackna over 2 years

    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 )

    • nosklo
      nosklo about 13 years
      Don't use ; at the end of your commands in python: It's ugly...
    • Arackna
      Arackna about 13 years
      I'll keep that in my mind , thanks !!
  • Mark Ransom
    Mark Ransom over 11 years
    To make sure the foreground contains transparency in all cases, use foreground.convert('RGBA') for the mask parameter.
  • Peter Hansen
    Peter Hansen almost 11 years
    I just used paste() to overlay one semi-transparent image on another, with PIL, and it worked as I expected. In what way doesn't it work as you expected?
  • Silouane Gerin
    Silouane Gerin over 10 years
    Thanks. I was too missing the third parameter.
  • homm
    homm over 9 years
    @PeterHansen, paste() doesn't work as expected "when the background image also contains transparency".
  • homm
    homm over 9 years
    @PeterHansen There is example: github.com/python-pillow/Pillow/issues/…
  • Peter Hansen
    Peter Hansen over 9 years
    @homm thanks. That was so long ago I have no memory of what I tried. It seems likely I did miss the part you quoted about the background image also having transparency.
  • physicalattraction
    physicalattraction almost 9 years
    Wow! This solution did the trick instantly two weeks ago, but now I totally forgot it already, and now I see it again, it again does the trick!
  • Deniz Ozger
    Deniz Ozger about 8 years
    I'm getting ValueError: bad transparency mask
  • William H. Hooper
    William H. Hooper almost 8 years
    Depending on your version, you may have to install the Python Image Library, and:' from PIL import Image`
  • Beatriz Fonseca
    Beatriz Fonseca over 7 years
    Amazing, you can use image as mask. But can I use vectorial images like svg?
  • digitaldavenyc
    digitaldavenyc over 7 years
    I get ValueError: image has wrong made as well @DenizOzger
  • Viet
    Viet about 7 years
    Thanks for the screenshots! Really helps!
  • Lian
    Lian almost 7 years
    This worked for me whereas paste was punching a "transparent hole" through my background.
  • Mithril
    Mithril almost 7 years
    But alpha_composite can not set the offset, would you mind to give an example to completely replace paste function?
  • P.Melch
    P.Melch almost 7 years
    I guess you would have to create a new empty image with the same size as the garget image, paste the layer at the proper position and use alpha_compositing to blend the new image over the target image.
  • Liviu Sosu
    Liviu Sosu over 6 years
    This one ascetically worked for me. The images must have exactly the same size, but it is ok. The paste function did not quite cut it for me ...
  • AFP_555
    AFP_555 about 6 years
    The secret sauce was tasty
  • Schütze
    Schütze almost 6 years
    'ValueError: images do not match'
  • Schütze
    Schütze almost 6 years
    TypeError: paste() got an unexpected keyword argument 'alpha'
  • nvd
    nvd over 5 years
    Possibly, they are of different dimensions. You may need to scale or crop one of those.
  • Mingwei Samuel
    Mingwei Samuel over 5 years
    @DenizOzger To fix ValueError: bad transparency mask use bg.paste(fg, (0, 0), fg.convert('RGBA'))
  • MilkyWay90
    MilkyWay90 about 5 years
    @Schütze see nvd's comment because he/she didn't ping (using @blahblah) you
  • jimf
    jimf about 5 years
    Hi, can you possibly add a little more context to your answer? Otherwise the requestor is not likely to learn the "why" behind it.
  • lllllllllllll
    lllllllllllll about 5 years
    ValueError: images do not match
  • user3613932
    user3613932 almost 5 years
    Thank you for indicating the information about the mask and the link to the documentation appreciate it.
  • Trect
    Trect over 4 years
    OMG!! I was trying some stupid login on cv2 to do this. In fact, spent 3 days on this. Love the secret sause
  • Trect
    Trect over 4 years
    ValueError: images do not match . Because this method works only when the image sizes are same
  • yota
    yota about 4 years
    this does not work as expected, it is not a proper overlay for a transparent image. fading transparency gives ugly results. It transparency is ON/OFF you should get what you expect though
  • Luis Jose
    Luis Jose almost 4 years
    Thank you for sharing. In my case "import Image" doesn't work. I had to use "from PIL import Image" instead.
  • Student
    Student almost 3 years
    I get: ValueError: images do not match
  • P.Melch
    P.Melch almost 3 years
    Images need to have the same size
  • Jordan The Genius
    Jordan The Genius about 2 years
    @Schütze I had to add these lines to avoid "images do not match": ` cloud_as_img.convert("RGBA") cloud_as_img.putalpha(255) cloud_as_img.save(temp_file_name) `