mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-02-05 06:00:58 +03:00
Merge pull request #2595 from wiredfool/issue_1911
Image.Image.alpha_composite Added
This commit is contained in:
commit
b9b5d39f2b
48
PIL/Image.py
48
PIL/Image.py
|
@ -1376,6 +1376,54 @@ class Image(object):
|
||||||
else:
|
else:
|
||||||
self.im.paste(im, box)
|
self.im.paste(im, box)
|
||||||
|
|
||||||
|
def alpha_composite(self, im, dest=(0,0), source=(0,0)):
|
||||||
|
""" 'In-place' analog of Image.alpha_composite. Composites an image
|
||||||
|
onto this image.
|
||||||
|
|
||||||
|
:param im: image to composite over this one
|
||||||
|
:param dest: Optional 2 tuple (top, left) specifying the upper
|
||||||
|
left corner in this (destination) image.
|
||||||
|
:param source: Optional 2 (top, left) tuple for the upper left
|
||||||
|
corner in the overlay source image, or 4 tuple (top, left, bottom,
|
||||||
|
right) for the bounds of the source rectangle
|
||||||
|
|
||||||
|
Performance Note: Not currently implemented in-place in the core layer.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not isinstance(source, tuple):
|
||||||
|
raise ValueError("Source must be a tuple")
|
||||||
|
if not isinstance(dest, tuple):
|
||||||
|
raise ValueError("Destination must be a tuple")
|
||||||
|
if not len(source) in (2, 4):
|
||||||
|
raise ValueError("Source must be a 2 or 4-tuple")
|
||||||
|
if not len(dest) == 2:
|
||||||
|
raise ValueError("Destination must be a 2-tuple")
|
||||||
|
if min(source) < 0:
|
||||||
|
raise ValueError("Source must be non-negative")
|
||||||
|
if min(dest) < 0:
|
||||||
|
raise ValueError("Destination must be non-negative")
|
||||||
|
|
||||||
|
if len(source) == 2:
|
||||||
|
source = source + im.size
|
||||||
|
|
||||||
|
# over image, crop if it's not the whole thing.
|
||||||
|
if source == (0,0) + im.size:
|
||||||
|
overlay = im
|
||||||
|
else:
|
||||||
|
overlay = im.crop(source)
|
||||||
|
|
||||||
|
# target for the paste
|
||||||
|
box = dest + (dest[0] + overlay.width, dest[1] + overlay.height)
|
||||||
|
|
||||||
|
# destination image. don't copy if we're using the whole image.
|
||||||
|
if dest == (0,0) + self.size:
|
||||||
|
background = self
|
||||||
|
else:
|
||||||
|
background = self.crop(box)
|
||||||
|
|
||||||
|
result = alpha_composite(background, overlay)
|
||||||
|
self.paste(result, box)
|
||||||
|
|
||||||
def point(self, lut, mode=None):
|
def point(self, lut, mode=None):
|
||||||
"""
|
"""
|
||||||
Maps this image through a lookup table or function.
|
Maps this image through a lookup table or function.
|
||||||
|
|
|
@ -202,6 +202,44 @@ class TestImage(PillowTestCase):
|
||||||
img_colors = sorted(img.getcolors())
|
img_colors = sorted(img.getcolors())
|
||||||
self.assertEqual(img_colors, expected_colors)
|
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), (0, 0, 32, 32))
|
||||||
|
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))
|
||||||
|
|
||||||
|
# source point
|
||||||
|
source = src.copy()
|
||||||
|
source.alpha_composite(over, (32, 32), (32, 32, 96, 96))
|
||||||
|
|
||||||
|
self.assert_image_equal(source.crop((32, 32, 96, 96)),
|
||||||
|
target.crop((32, 32, 96, 96)))
|
||||||
|
self.assertEqual(source.size, (128, 128))
|
||||||
|
|
||||||
def test_registered_extensions_uninitialized(self):
|
def test_registered_extensions_uninitialized(self):
|
||||||
# Arrange
|
# Arrange
|
||||||
Image._initialized = 0
|
Image._initialized = 0
|
||||||
|
|
|
@ -104,6 +104,8 @@ An instance of the :py:class:`~PIL.Image.Image` class has the following
|
||||||
methods. Unless otherwise stated, all methods return a new instance of the
|
methods. Unless otherwise stated, all methods return a new instance of the
|
||||||
:py:class:`~PIL.Image.Image` class, holding the resulting image.
|
:py:class:`~PIL.Image.Image` class, holding the resulting image.
|
||||||
|
|
||||||
|
|
||||||
|
.. automethod:: PIL.Image.Image.alpha_composite
|
||||||
.. automethod:: PIL.Image.Image.convert
|
.. automethod:: PIL.Image.Image.convert
|
||||||
|
|
||||||
The following example converts an RGB image (linearly calibrated according to
|
The following example converts an RGB image (linearly calibrated according to
|
||||||
|
|
Loading…
Reference in New Issue
Block a user