mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-03-03 19:45:56 +03:00
Merge pull request #5417 from radarhere/contain
Added ImageOps contain()
This commit is contained in:
commit
8a8ac60817
|
@ -37,6 +37,9 @@ def test_sanity():
|
||||||
ImageOps.pad(hopper("L"), (128, 128))
|
ImageOps.pad(hopper("L"), (128, 128))
|
||||||
ImageOps.pad(hopper("RGB"), (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("L"), 1)
|
||||||
ImageOps.crop(hopper("RGB"), 1)
|
ImageOps.crop(hopper("RGB"), 1)
|
||||||
|
|
||||||
|
@ -99,6 +102,13 @@ def test_fit_same_ratio():
|
||||||
assert new_im.size == (1000, 755)
|
assert new_im.size == (1000, 755)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("new_size", ((256, 256), (512, 256), (256, 512)))
|
||||||
|
def test_contain(new_size):
|
||||||
|
im = hopper()
|
||||||
|
new_im = ImageOps.contain(im, new_size)
|
||||||
|
assert new_im.size == (256, 256)
|
||||||
|
|
||||||
|
|
||||||
def test_pad():
|
def test_pad():
|
||||||
# Same ratio
|
# Same ratio
|
||||||
im = hopper()
|
im = hopper()
|
||||||
|
|
|
@ -12,6 +12,7 @@ only work on L and RGB images.
|
||||||
|
|
||||||
.. autofunction:: autocontrast
|
.. autofunction:: autocontrast
|
||||||
.. autofunction:: colorize
|
.. autofunction:: colorize
|
||||||
|
.. autofunction:: contain
|
||||||
.. autofunction:: pad
|
.. autofunction:: pad
|
||||||
.. autofunction:: crop
|
.. autofunction:: crop
|
||||||
.. autofunction:: scale
|
.. autofunction:: scale
|
||||||
|
|
64
docs/releasenotes/8.3.0.rst
Normal file
64
docs/releasenotes/8.3.0.rst
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
8.3.0
|
||||||
|
-----
|
||||||
|
|
||||||
|
Deprecations
|
||||||
|
============
|
||||||
|
|
||||||
|
TODO
|
||||||
|
^^^^
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
API Changes
|
||||||
|
===========
|
||||||
|
|
||||||
|
Changed WebP default "method" value when saving
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Previously, it was 0, for the best speed. The default has now been changed to 4, to
|
||||||
|
match WebP's default, for higher quality with still some speed optimisation.
|
||||||
|
|
||||||
|
Default resampling filter for special image modes
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Pillow 7.0 changed the default resampling filter to ``Image.BICUBIC``. However, as this
|
||||||
|
is not supported yet for images with a custom number of bits, the default filter for
|
||||||
|
those modes has been reverted to ``Image.NEAREST``.
|
||||||
|
|
||||||
|
ImageMorph incorrect mode errors
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
For ``apply()``, ``match()`` and ``get_on_pixels()``, if the image mode is not L, an
|
||||||
|
:py:exc:`Exception` was thrown. This has now been changed to a :py:exc:`ValueError`.
|
||||||
|
|
||||||
|
API Additions
|
||||||
|
=============
|
||||||
|
|
||||||
|
ImageOps.contain
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Returns a resized version of the image, set to the maximum width and height within
|
||||||
|
``size``, while maintaining the original aspect ratio.
|
||||||
|
|
||||||
|
To compare it to other ImageOps methods:
|
||||||
|
|
||||||
|
- :py:meth:`~PIL.ImageOps.fit` expands an image until is fills ``size``, cropping the
|
||||||
|
parts of the image that do not fit.
|
||||||
|
- :py:meth:`~PIL.ImageOps.pad` expands an image to fill ``size``, without cropping, but
|
||||||
|
instead filling the extra space with ``color``.
|
||||||
|
- :py:meth:`~PIL.ImageOps.contain` is similar to :py:meth:`~PIL.ImageOps.pad`, but it
|
||||||
|
does not fill the extra space. Instead, the original aspect ratio is maintained. So
|
||||||
|
unlike the other two methods, it is not guaranteed to return an image of ``size``.
|
||||||
|
|
||||||
|
Security
|
||||||
|
========
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
Other Changes
|
||||||
|
=============
|
||||||
|
|
||||||
|
TODO
|
||||||
|
^^^^
|
||||||
|
|
||||||
|
TODO
|
|
@ -14,6 +14,7 @@ expected to be backported to earlier versions.
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
|
8.3.0
|
||||||
8.2.0
|
8.2.0
|
||||||
8.1.2
|
8.1.2
|
||||||
8.1.1
|
8.1.1
|
||||||
|
|
|
@ -236,15 +236,43 @@ def colorize(image, black, white, mid=None, blackpoint=0, whitepoint=255, midpoi
|
||||||
return _lut(image, red + green + blue)
|
return _lut(image, red + green + blue)
|
||||||
|
|
||||||
|
|
||||||
def pad(image, size, method=Image.BICUBIC, color=None, centering=(0.5, 0.5)):
|
def contain(image, size, method=Image.BICUBIC):
|
||||||
"""
|
"""
|
||||||
Returns a sized and padded version of the image, expanded to fill the
|
Returns a resized version of the image, set to the maximum width and height
|
||||||
requested aspect ratio and size.
|
within the requested size, while maintaining the original aspect ratio.
|
||||||
|
|
||||||
:param image: The image to size and crop.
|
:param image: The image to resize and crop.
|
||||||
: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: What resampling method to use. Default is
|
:param method: 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 resized and padded version of the image, expanded to fill the
|
||||||
|
requested aspect ratio and size.
|
||||||
|
|
||||||
|
:param image: The image to resize and crop.
|
||||||
|
: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.BICUBIC`. See :ref:`concept-filters`.
|
:py:attr:`PIL.Image.BICUBIC`. See :ref:`concept-filters`.
|
||||||
:param color: The background color of the padded image.
|
:param color: The background color of the padded image.
|
||||||
:param centering: Control the position of the original image within the
|
:param centering: Control the position of the original image within the
|
||||||
|
@ -257,27 +285,17 @@ def pad(image, size, method=Image.BICUBIC, color=None, centering=(0.5, 0.5)):
|
||||||
:return: An image.
|
:return: An image.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
im_ratio = image.width / image.height
|
resized = contain(image, size, method)
|
||||||
dest_ratio = size[0] / size[1]
|
if resized.size == size:
|
||||||
|
out = resized
|
||||||
if im_ratio == dest_ratio:
|
|
||||||
out = image.resize(size, resample=method)
|
|
||||||
else:
|
else:
|
||||||
out = Image.new(image.mode, size, color)
|
out = Image.new(image.mode, size, color)
|
||||||
if im_ratio > dest_ratio:
|
if resized.width != size[0]:
|
||||||
new_height = int(image.height / image.width * size[0])
|
x = int((size[0] - resized.width) * max(0, min(centering[0], 1)))
|
||||||
if new_height != size[1]:
|
out.paste(resized, (x, 0))
|
||||||
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))
|
|
||||||
else:
|
else:
|
||||||
new_width = int(image.width / image.height * size[1])
|
y = int((size[1] - resized.height) * max(0, min(centering[1], 1)))
|
||||||
if new_width != size[0]:
|
out.paste(resized, (0, y))
|
||||||
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))
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
@ -304,7 +322,7 @@ def scale(image, factor, resample=Image.BICUBIC):
|
||||||
|
|
||||||
:param image: The image to rescale.
|
:param image: The image to rescale.
|
||||||
:param factor: The expansion factor, as a float.
|
:param factor: The expansion factor, as a float.
|
||||||
:param resample: What resampling method to use. Default is
|
:param resample: Resampling method to use. Default is
|
||||||
:py:attr:`PIL.Image.BICUBIC`. See :ref:`concept-filters`.
|
:py:attr:`PIL.Image.BICUBIC`. See :ref:`concept-filters`.
|
||||||
:returns: An :py:class:`~PIL.Image.Image` object.
|
:returns: An :py:class:`~PIL.Image.Image` object.
|
||||||
"""
|
"""
|
||||||
|
@ -381,15 +399,15 @@ def expand(image, border=0, fill=0):
|
||||||
|
|
||||||
def fit(image, size, method=Image.BICUBIC, bleed=0.0, centering=(0.5, 0.5)):
|
def fit(image, size, method=Image.BICUBIC, bleed=0.0, centering=(0.5, 0.5)):
|
||||||
"""
|
"""
|
||||||
Returns a sized and cropped version of the image, cropped to the
|
Returns a resized and cropped version of the image, cropped to the
|
||||||
requested aspect ratio and size.
|
requested aspect ratio and size.
|
||||||
|
|
||||||
This function was contributed by Kevin Cazabon.
|
This function was contributed by Kevin Cazabon.
|
||||||
|
|
||||||
:param image: The image to size and crop.
|
:param image: The image to resize and crop.
|
||||||
: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: What resampling method to use. Default is
|
:param method: Resampling method to use. Default is
|
||||||
:py:attr:`PIL.Image.BICUBIC`. See :ref:`concept-filters`.
|
:py:attr:`PIL.Image.BICUBIC`. See :ref:`concept-filters`.
|
||||||
:param bleed: Remove a border around the outside of the image from all
|
:param bleed: Remove a border around the outside of the image from all
|
||||||
four edges. The value is a decimal percentage (use 0.01 for
|
four edges. The value is a decimal percentage (use 0.01 for
|
||||||
|
|
Loading…
Reference in New Issue
Block a user