diff --git a/PIL/Image.py b/PIL/Image.py index 9936aad46..27953252a 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -1373,6 +1373,34 @@ class Image(object): else: self.im.paste(im, box) + def alpha_composite(self, im, box=None): + """ 'In-place' analog of Image.alpha_composite + + :param im: image to composite over this one + :param box: Optional 2 or 4 tuple. If a 2 tuple, the upper + left corner. If 4 tuple, (x0,y0,x1,y1) + + Note: Not currently implemented in-place. + """ + if box is None: + box = (0, 0, im.width, im.height) + overlay = im + if self.size == im.size: + src = self + else: + src = self.crop(box) + else: + if len(box) == 2: + # upper left corner given; get size from overlay image + size = im.size + box += (box[0]+size[0], box[1]+size[1]) + + src = self.crop(box) + overlay = im.crop((0, 0, box[2]-box[0], box[3]-box[1])) + + result = alpha_composite(src, overlay) + self.paste(result, box) + def point(self, lut, mode=None): """ Maps this image through a lookup table or function. diff --git a/Tests/test_image.py b/Tests/test_image.py index ea813cd84..05fb4dfe9 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -202,6 +202,37 @@ class TestImage(PillowTestCase): img_colors = sorted(img.getcolors()) self.assertEqual(img_colors, expected_colors) + def test_alpha_inplace(self): + src = Image.new('RGBA', (128,128), 'blue') + + over = Image.new('RGBA', (128,128), 'red') + mask = hopper('L') + over.putalpha(mask) + + target = Image.alpha_composite(src, over) + + # basic + full = src.copy() + full.alpha_composite(over) + self.assert_image_equal(full, target) + + # with offset down to right + offset = src.copy() + offset.alpha_composite(over, (64, 64)) + self.assert_image_equal(offset.crop((64, 64, 127, 127)), + target.crop((0, 0, 63, 63))) + self.assertEqual(offset.size, (128, 128)) + + # offset and crop + box = src.copy() + box.alpha_composite(over, (64, 64, 96, 96)) + self.assert_image_equal(box.crop((64, 64, 96, 96)), + target.crop((0, 0, 32, 32))) + self.assert_image_equal(box.crop((96, 96, 128, 128)), + src.crop((0, 0, 32, 32))) + self.assertEqual(box.size, (128, 128)) + + def test_registered_extensions_uninitialized(self): # Arrange Image._initialized = 0