Added contain method

This commit is contained in:
Andrew Murray 2021-04-19 20:12:52 +10:00
parent fc08a72600
commit 40eceec70d
2 changed files with 54 additions and 18 deletions

View File

@ -37,6 +37,9 @@ def test_sanity():
ImageOps.pad(hopper("L"), (128, 128))
ImageOps.pad(hopper("RGB"), (128, 128))
ImageOps.contain(hopper("L"), (128, 128))
ImageOps.contain(hopper("RGB"), (128, 128))
ImageOps.crop(hopper("L"), 1)
ImageOps.crop(hopper("RGB"), 1)
@ -99,6 +102,21 @@ def test_fit_same_ratio():
assert new_im.size == (1000, 755)
def test_contain():
# Same ratio
im = hopper()
new_size = (im.width * 2, im.height * 2)
new_im = ImageOps.contain(im, new_size)
assert new_im.size == new_size
for new_size in [
(im.width * 4, im.height * 2),
(im.width * 2, im.height * 4),
]:
new_im = ImageOps.contain(im, new_size)
assert new_im.size == (im.width * 2, im.height * 2)
def test_pad():
# Same ratio
im = hopper()

View File

@ -236,6 +236,34 @@ def colorize(image, black, white, mid=None, blackpoint=0, whitepoint=255, midpoi
return _lut(image, red + green + blue)
def contain(image, size, method=Image.BICUBIC):
"""
Returns a sized version of the image, expanded to fill the requested aspect ratio
and size.
:param image: The image to size and crop.
:param size: The requested output size in pixels, given as a
(width, height) tuple.
:param method: What resampling method to use. Default is
:py:attr:`PIL.Image.BICUBIC`. See :ref:`concept-filters`.
:return: An image.
"""
im_ratio = image.width / image.height
dest_ratio = size[0] / size[1]
if im_ratio != dest_ratio:
if im_ratio > dest_ratio:
new_height = int(image.height / image.width * size[0])
if new_height != size[1]:
size = (size[0], new_height)
else:
new_width = int(image.width / image.height * size[1])
if new_width != size[0]:
size = (new_width, size[1])
return image.resize(size, resample=method)
def pad(image, size, method=Image.BICUBIC, color=None, centering=(0.5, 0.5)):
"""
Returns a sized and padded version of the image, expanded to fill the
@ -257,27 +285,17 @@ def pad(image, size, method=Image.BICUBIC, color=None, centering=(0.5, 0.5)):
:return: An image.
"""
im_ratio = image.width / image.height
dest_ratio = size[0] / size[1]
if im_ratio == dest_ratio:
out = image.resize(size, resample=method)
resized = contain(image, size, method)
if resized.size == size:
out = resized
else:
out = Image.new(image.mode, size, color)
if im_ratio > dest_ratio:
new_height = int(image.height / image.width * size[0])
if new_height != size[1]:
image = image.resize((size[0], new_height), resample=method)
y = int((size[1] - new_height) * max(0, min(centering[1], 1)))
out.paste(image, (0, y))
if resized.width != size[0]:
x = int((size[0] - resized.width) * max(0, min(centering[0], 1)))
out.paste(resized, (x, 0))
else:
new_width = int(image.width / image.height * size[1])
if new_width != size[0]:
image = image.resize((new_width, size[1]), resample=method)
x = int((size[0] - new_width) * max(0, min(centering[0], 1)))
out.paste(image, (x, 0))
y = int((size[1] - resized.height) * max(0, min(centering[1], 1)))
out.paste(resized, (0, y))
return out