Merging PIL of two images with alpha channels - does not work as expected

There are tons of SO questions here that provide answers to this question, but the conclusion is not expected.

The goal is to combine two RGBA images. The alpha channel information of each image is not the same.

Current (simplified) code:

from PIL import Image image = '1.png' watermark = '2.png' wmark = Image.open(watermark) img = Image.open(image) img.paste(wmark, (0, 0), wmark) img.save("result.png", "PNG") 

Two images:

Background

Background

Foreground

Foreground

Expected Result

Expected output

Actual result

Actual result

If you don't see the difference, here are the alpha channels (inverted for better visualization) of the final versions.

Expected Result - Alpha Channel

Expected result - alpha channel

Actual Result - Alpha Channel

Actual result - alpha channel

So, with that said, is there a way to do this, or am I doing something wrong?

EDIT - clarification after @zenpoy comment:

If the foreground image has a certain amount of opacity, I want this to be taken into account when overlapping both images, but I do not want the alpha channel of the second image to be added to the first. It is very similar to putting a piece of glass (foreground image) in front of the image on paper (background).

In other words, if the background image was RGB instead of RGBA, the final image should not have alpha information.

+4
source share
1 answer

From your initial description, the following idea seems equivalent. Let X, Y be two RGBA images. Combine X and Y by looking at the RGB stripes from X and the RGBA stripes from Y, creating an image of Z. Set the range A to Z relative to the strip A to X. This contradicts your final statement, but seems to give the expected output in this situation.

So this is the code:

 image = '1.png' watermark = '2.png' wmark = Image.open(watermark) img = Image.open(image) ia, wa = None, None if len(img.getbands()) == 4: ir, ig, ib, ia = img.split() img = Image.merge('RGB', (ir, ig, ib)) if len(wmark.getbands()) == 4: wa = wmark.split()[-1] img.paste(wmark, (0, 0), wmark) if ia: if wa: # XXX This seems to solve the contradiction, discard if unwanted. ia = max_alpha(wa, ia) img.putalpha(ia) img.save('result.png') 

where the max_alpha function is:

 def max_alpha(a, b): # Assumption: 'a' and 'b' are of same size im_a = a.load() im_b = b.load() width, height = a.size alpha = Image.new('L', (width, height)) im = alpha.load() for x in xrange(width): for y in xrange(height): im[x, y] = max(im_a[x, y], im_b[x, y]) return alpha 

This new feature seems to account for this contradiction.

+3
source

All Articles