Merge pull request #8352 from radarhere/scale

This commit is contained in:
Hugo van Kemenade 2024-09-10 14:38:33 +03:00 committed by GitHub
commit e91aedb65d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 76 additions and 41 deletions

View File

@ -63,8 +63,8 @@ def test_save_append_images(tmp_path: Path) -> None:
assert_image_similar_tofile(im, temp_file, 1) assert_image_similar_tofile(im, temp_file, 1)
with Image.open(temp_file) as reread: with Image.open(temp_file) as reread:
reread.size = (16, 16, 2) reread.size = (16, 16)
reread.load() reread.load(2)
assert_image_equal(reread, provided_im) assert_image_equal(reread, provided_im)
@ -87,14 +87,21 @@ def test_sizes() -> None:
for w, h, r in im.info["sizes"]: for w, h, r in im.info["sizes"]:
wr = w * r wr = w * r
hr = h * r hr = h * r
with pytest.warns(DeprecationWarning):
im.size = (w, h, r) im.size = (w, h, r)
im.load() im.load()
assert im.mode == "RGBA" assert im.mode == "RGBA"
assert im.size == (wr, hr) assert im.size == (wr, hr)
# Test using load() with scale
im.size = (w, h)
im.load(scale=r)
assert im.mode == "RGBA"
assert im.size == (wr, hr)
# Check that we cannot load an incorrect size # Check that we cannot load an incorrect size
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.size = (1, 1) im.size = (1, 2)
def test_older_icon() -> None: def test_older_icon() -> None:
@ -105,8 +112,8 @@ def test_older_icon() -> None:
wr = w * r wr = w * r
hr = h * r hr = h * r
with Image.open("Tests/images/pillow2.icns") as im2: with Image.open("Tests/images/pillow2.icns") as im2:
im2.size = (w, h, r) im2.size = (w, h)
im2.load() im2.load(r)
assert im2.mode == "RGBA" assert im2.mode == "RGBA"
assert im2.size == (wr, hr) assert im2.size == (wr, hr)
@ -122,8 +129,8 @@ def test_jp2_icon() -> None:
wr = w * r wr = w * r
hr = h * r hr = h * r
with Image.open("Tests/images/pillow3.icns") as im2: with Image.open("Tests/images/pillow3.icns") as im2:
im2.size = (w, h, r) im2.size = (w, h)
im2.load() im2.load(r)
assert im2.mode == "RGBA" assert im2.mode == "RGBA"
assert im2.size == (wr, hr) assert im2.size == (wr, hr)

View File

@ -122,6 +122,14 @@ vulnerability introduced in FreeType 2.6 (:cve:`2020-15999`).
.. _2.10.4: https://sourceforge.net/projects/freetype/files/freetype2/2.10.4/ .. _2.10.4: https://sourceforge.net/projects/freetype/files/freetype2/2.10.4/
ICNS (width, height, scale) sizes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. deprecated:: 11.0.0
Setting an ICNS image size to ``(width, height, scale)`` before loading has been
deprecated. Instead, ``load(scale)`` can be used.
Image isImageType() Image isImageType()
^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^

View File

@ -324,12 +324,19 @@ sets the following :py:attr:`~PIL.Image.Image.info` property:
**sizes** **sizes**
A list of supported sizes found in this icon file; these are a A list of supported sizes found in this icon file; these are a
3-tuple, ``(width, height, scale)``, where ``scale`` is 2 for a retina 3-tuple, ``(width, height, scale)``, where ``scale`` is 2 for a retina
icon and 1 for a standard icon. You *are* permitted to use this 3-tuple icon and 1 for a standard icon.
format for the :py:attr:`~PIL.Image.Image.size` property if you set it
before calling :py:meth:`~PIL.Image.Image.load`; after loading, the size .. _icns-loading:
will be reset to a 2-tuple containing pixel dimensions (so, e.g. if you
ask for ``(512, 512, 2)``, the final value of Loading
:py:attr:`~PIL.Image.Image.size` will be ``(1024, 1024)``). ~~~~~~~
You can call the :py:meth:`~PIL.Image.Image.load` method with the following parameter.
**scale**
Affects the scale of the resultant image. If the size is set to ``(512, 512)``,
after loading at scale 2, the final value of :py:attr:`~PIL.Image.Image.size` will
be ``(1024, 1024)``.
.. _icns-saving: .. _icns-saving:

View File

@ -61,6 +61,14 @@ vulnerability introduced in FreeType 2.6 (:cve:`2020-15999`).
.. _2.10.4: https://sourceforge.net/projects/freetype/files/freetype2/2.10.4/ .. _2.10.4: https://sourceforge.net/projects/freetype/files/freetype2/2.10.4/
ICNS (width, height, scale) sizes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. deprecated:: 11.0.0
Setting an ICNS image size to ``(width, height, scale)`` before loading has been
deprecated. Instead, ``load(scale)`` can be used.
Image isImageType() Image isImageType()
^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
@ -72,6 +80,8 @@ instead.
ImageMath.lambda_eval and ImageMath.unsafe_eval options parameter ImageMath.lambda_eval and ImageMath.unsafe_eval options parameter
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. deprecated:: 11.0.0
The ``options`` parameter in :py:meth:`~PIL.ImageMath.lambda_eval()` and The ``options`` parameter in :py:meth:`~PIL.ImageMath.lambda_eval()` and
:py:meth:`~PIL.ImageMath.unsafe_eval()` has been deprecated. One or more :py:meth:`~PIL.ImageMath.unsafe_eval()` has been deprecated. One or more
keyword arguments can be used instead. keyword arguments can be used instead.
@ -87,6 +97,8 @@ have been deprecated, and will be removed in Pillow 12 (2025-10-15).
Specific WebP Feature Checks Specific WebP Feature Checks
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. deprecated:: 11.0.0
``features.check("transp_webp")``, ``features.check("webp_mux")`` and ``features.check("transp_webp")``, ``features.check("webp_mux")`` and
``features.check("webp_anim")`` are now deprecated. They will always return ``features.check("webp_anim")`` are now deprecated. They will always return
``True`` if the WebP module is installed, until they are removed in Pillow ``True`` if the WebP module is installed, until they are removed in Pillow

View File

@ -25,6 +25,7 @@ import sys
from typing import IO from typing import IO
from . import Image, ImageFile, PngImagePlugin, features from . import Image, ImageFile, PngImagePlugin, features
from ._deprecate import deprecate
enable_jpeg2k = features.check_codec("jpg_2000") enable_jpeg2k = features.check_codec("jpg_2000")
if enable_jpeg2k: if enable_jpeg2k:
@ -275,37 +276,37 @@ class IcnsImageFile(ImageFile.ImageFile):
self.best_size[1] * self.best_size[2], self.best_size[1] * self.best_size[2],
) )
@property @property # type: ignore[override]
def size(self): def size(self) -> tuple[int, int] | tuple[int, int, int]:
return self._size return self._size
@size.setter @size.setter
def size(self, value) -> None: def size(self, value: tuple[int, int] | tuple[int, int, int]) -> None:
info_size = value if len(value) == 3:
if info_size not in self.info["sizes"] and len(info_size) == 2: deprecate("Setting size to (width, height, scale)", 12, "load(scale)")
info_size = (info_size[0], info_size[1], 1) if value in self.info["sizes"]:
if ( self._size = value # type: ignore[assignment]
info_size not in self.info["sizes"] return
and len(info_size) == 3 else:
and info_size[2] == 1 # Check that a matching size exists,
): # or that there is a scale that would create a size that matches
simple_sizes = [ for size in self.info["sizes"]:
(size[0] * size[2], size[1] * size[2]) for size in self.info["sizes"] simple_size = size[0] * size[2], size[1] * size[2]
] scale = simple_size[0] // value[0]
if value in simple_sizes: if simple_size[1] / value[1] == scale:
info_size = self.info["sizes"][simple_sizes.index(value)] self._size = value
if info_size not in self.info["sizes"]: return
msg = "This is not one of the allowed sizes of this image" msg = "This is not one of the allowed sizes of this image"
raise ValueError(msg) raise ValueError(msg)
self._size = value
def load(self) -> Image.core.PixelAccess | None: def load(self, scale: int | None = None) -> Image.core.PixelAccess | None:
if len(self.size) == 3: if scale is not None or len(self.size) == 3:
self.best_size = self.size if scale is None and len(self.size) == 3:
self.size = ( scale = self.size[2]
self.best_size[0] * self.best_size[2], assert scale is not None
self.best_size[1] * self.best_size[2], width, height = self.size[:2]
) self.size = width * scale, height * scale
self.best_size = width, height, scale
px = Image.Image.load(self) px = Image.Image.load(self)
if self._im is not None and self.im.size == self.size: if self._im is not None and self.im.size == self.size: