Merge pull request #7412 from radarhere/cover

Added ImageOps cover method
This commit is contained in:
mergify[bot] 2023-10-13 22:16:30 +00:00 committed by GitHub
commit a4bc7146e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 122 additions and 4 deletions

View File

@ -39,6 +39,9 @@ def test_sanity():
ImageOps.contain(hopper("L"), (128, 128)) ImageOps.contain(hopper("L"), (128, 128))
ImageOps.contain(hopper("RGB"), (128, 128)) ImageOps.contain(hopper("RGB"), (128, 128))
ImageOps.cover(hopper("L"), (128, 128))
ImageOps.cover(hopper("RGB"), (128, 128))
ImageOps.crop(hopper("L"), 1) ImageOps.crop(hopper("L"), 1)
ImageOps.crop(hopper("RGB"), 1) ImageOps.crop(hopper("RGB"), 1)
@ -119,6 +122,20 @@ def test_contain_round():
assert new_im.height == 5 assert new_im.height == 5
@pytest.mark.parametrize(
"image_name, expected_size",
(
("colr_bungee.png", (1024, 256)), # landscape
("imagedraw_stroke_multiline.png", (256, 640)), # portrait
("hopper.png", (256, 256)), # square
),
)
def test_cover(image_name, expected_size):
with Image.open("Tests/images/" + image_name) as im:
new_im = ImageOps.cover(im, (256, 256))
assert new_im.size == expected_size
def test_pad(): def test_pad():
# Same ratio # Same ratio
im = hopper() im = hopper()

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -268,6 +268,37 @@ true, to provide for the same changes to the image's size.
A more general form of image transformations can be carried out via the A more general form of image transformations can be carried out via the
:py:meth:`~PIL.Image.Image.transform` method. :py:meth:`~PIL.Image.Image.transform` method.
Relative resizing
^^^^^^^^^^^^^^^^^
Instead of calculating the size of the new image when resizing, you can also
choose to resize relative to a given size.
::
from PIL import Image, ImageOps
size = (100, 150)
with Image.open("Tests/images/hopper.png") as im:
ImageOps.contain(im, size).save("imageops_contain.png")
ImageOps.cover(im, size).save("imageops_cover.png")
ImageOps.fit(im, size).save("imageops_fit.png")
ImageOps.pad(im, size, color="#f00").save("imageops_pad.png")
# thumbnail() can also be used,
# but will modify the image object in place
im.thumbnail(size)
im.save("imageops_thumbnail.png")
+----------------+-------------------------------------------+--------------------------------------------+------------------------------------------+----------------------------------------+----------------------------------------+
| | :py:meth:`~PIL.Image.Image.thumbnail` | :py:meth:`~PIL.ImageOps.contain` | :py:meth:`~PIL.ImageOps.cover` | :py:meth:`~PIL.ImageOps.fit` | :py:meth:`~PIL.ImageOps.pad` |
+================+===========================================+============================================+==========================================+========================================+========================================+
|Given size | ``(150, 100)`` | ``(150, 100)`` | ``(150, 150)`` | ``(150, 100)`` | ``(150, 100)`` |
+----------------+-------------------------------------------+--------------------------------------------+------------------------------------------+----------------------------------------+----------------------------------------+
|Resulting image | .. image:: ../example/image_thumbnail.png | .. image:: ../example/imageops_contain.png | .. image:: ../example/imageops_cover.png | .. image:: ../example/imageops_fit.png | .. image:: ../example/imageops_pad.png |
+----------------+-------------------------------------------+--------------------------------------------+------------------------------------------+----------------------------------------+----------------------------------------+
|Resulting size | ``100×100`` | ``100×100`` | ``150×150`` | ``150×100`` | ``150×100`` |
+----------------+-------------------------------------------+--------------------------------------------+------------------------------------------+----------------------------------------+----------------------------------------+
.. _color-transforms: .. _color-transforms:
Color transforms Color transforms

View File

@ -12,14 +12,11 @@ only work on L and RGB images.
.. autofunction:: autocontrast .. autofunction:: autocontrast
.. autofunction:: colorize .. autofunction:: colorize
.. autofunction:: contain
.. autofunction:: pad
.. autofunction:: crop .. autofunction:: crop
.. autofunction:: scale .. autofunction:: scale
.. autofunction:: deform .. autofunction:: deform
.. autofunction:: equalize .. autofunction:: equalize
.. autofunction:: expand .. autofunction:: expand
.. autofunction:: fit
.. autofunction:: flip .. autofunction:: flip
.. autofunction:: grayscale .. autofunction:: grayscale
.. autofunction:: invert .. autofunction:: invert
@ -27,3 +24,38 @@ only work on L and RGB images.
.. autofunction:: posterize .. autofunction:: posterize
.. autofunction:: solarize .. autofunction:: solarize
.. autofunction:: exif_transpose .. autofunction:: exif_transpose
.. _relative-resize:
Resize relative to a given size
-------------------------------
::
from PIL import Image, ImageOps
size = (100, 150)
with Image.open("Tests/images/hopper.png") as im:
ImageOps.contain(im, size).save("imageops_contain.png")
ImageOps.cover(im, size).save("imageops_cover.png")
ImageOps.fit(im, size).save("imageops_fit.png")
ImageOps.pad(im, size, color="#f00").save("imageops_pad.png")
# thumbnail() can also be used,
# but will modify the image object in place
im.thumbnail(size)
im.save("imageops_thumbnail.png")
+----------------+-------------------------------------------+--------------------------------------------+------------------------------------------+----------------------------------------+----------------------------------------+
| | :py:meth:`~PIL.Image.Image.thumbnail` | :py:meth:`~PIL.ImageOps.contain` | :py:meth:`~PIL.ImageOps.cover` | :py:meth:`~PIL.ImageOps.fit` | :py:meth:`~PIL.ImageOps.pad` |
+================+===========================================+============================================+==========================================+========================================+========================================+
|Given size | ``(150, 100)`` | ``(150, 100)`` | ``(150, 150)`` | ``(150, 100)`` | ``(150, 100)`` |
+----------------+-------------------------------------------+--------------------------------------------+------------------------------------------+----------------------------------------+----------------------------------------+
|Resulting image | .. image:: ../example/image_thumbnail.png | .. image:: ../example/imageops_contain.png | .. image:: ../example/imageops_cover.png | .. image:: ../example/imageops_fit.png | .. image:: ../example/imageops_pad.png |
+----------------+-------------------------------------------+--------------------------------------------+------------------------------------------+----------------------------------------+----------------------------------------+
|Resulting size | ``100×100`` | ``100×100`` | ``150×150`` | ``150×100`` | ``150×100`` |
+----------------+-------------------------------------------+--------------------------------------------+------------------------------------------+----------------------------------------+----------------------------------------+
.. autofunction:: contain
.. autofunction:: cover
.. autofunction:: fit
.. autofunction:: pad

View File

@ -41,6 +41,15 @@ to be specified, rather than a single number for both dimensions. ::
API Additions API Additions
============= =============
ImageOps.cover
^^^^^^^^^^^^^^
Returns a resized version of the image, so that the requested size is covered,
while maintaining the original aspect ratio.
See :ref:`relative-resize` for a comparison between this and similar ``ImageOps``
methods.
EpsImagePlugin.gs_binary EpsImagePlugin.gs_binary
^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -242,7 +242,7 @@ def contain(image, size, method=Image.Resampling.BICUBIC):
Returns a resized version of the image, set to the maximum width and height Returns a resized version of the image, set to the maximum width and height
within the requested size, while maintaining the original aspect ratio. within the requested size, while maintaining the original aspect ratio.
:param image: The image to resize and crop. :param image: The image to resize.
:param size: The requested output size in pixels, given as a :param size: The requested output size in pixels, given as a
(width, height) tuple. (width, height) tuple.
:param method: Resampling method to use. Default is :param method: Resampling method to use. Default is
@ -266,6 +266,35 @@ def contain(image, size, method=Image.Resampling.BICUBIC):
return image.resize(size, resample=method) return image.resize(size, resample=method)
def cover(image, size, method=Image.Resampling.BICUBIC):
"""
Returns a resized version of the image, so that the requested size is
covered, while maintaining the original aspect ratio.
:param image: The image to resize.
:param size: The requested output size in pixels, given as a
(width, height) tuple.
:param method: Resampling method to use. Default is
:py:attr:`~PIL.Image.Resampling.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 = round(image.height / image.width * size[0])
if new_height != size[1]:
size = (size[0], new_height)
else:
new_width = round(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.Resampling.BICUBIC, color=None, centering=(0.5, 0.5)): def pad(image, size, method=Image.Resampling.BICUBIC, color=None, centering=(0.5, 0.5)):
""" """
Returns a resized and padded version of the image, expanded to fill the Returns a resized and padded version of the image, expanded to fill the