Merge branch 'main' into enum

This commit is contained in:
Andrew Murray 2022-02-15 08:12:28 +11:00 committed by GitHub
commit 9a4106c14f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 147 additions and 25 deletions

View File

@ -5,6 +5,12 @@ Changelog (Pillow)
9.1.0 (unreleased)
------------------
- Added get_photoshop_blocks() to parse Photoshop TIFF tag #6030
[radarhere]
- Drop excess values in BITSPERSAMPLE #6041
[mikhail-iurkov]
- Added unpacker from RGBA;15 to RGB #6031
[radarhere]
@ -26,7 +32,7 @@ Changelog (Pillow)
- Ensure duplicated file pointer is closed #5946
[radarhere]
- Added specific error if ImagePath coordinate type is incorrect #5942
- Added specific error if path coordinate type is incorrect #5942
[radarhere]
- Return an empty bytestring from tobytes() for an empty image #5938

Binary file not shown.

View File

@ -90,11 +90,18 @@ class TestFileTiff:
assert_image_similar_tofile(im, "Tests/images/pil136.png", 1)
def test_wrong_bits_per_sample(self):
with Image.open("Tests/images/tiff_wrong_bits_per_sample.tiff") as im:
assert im.mode == "RGBA"
assert im.size == (52, 53)
assert im.tile == [("raw", (0, 0, 52, 53), 160, ("RGBA", 0, 1))]
@pytest.mark.parametrize(
"file_name,mode,size,offset",
[
("tiff_wrong_bits_per_sample.tiff", "RGBA", (52, 53), 160),
("tiff_wrong_bits_per_sample_2.tiff", "RGB", (16, 16), 8),
],
)
def test_wrong_bits_per_sample(self, file_name, mode, size, offset):
with Image.open("Tests/images/" + file_name) as im:
assert im.mode == mode
assert im.size == size
assert im.tile == [("raw", (0, 0) + size, offset, (mode, 0, 1))]
im.load()
def test_set_legacy_api(self):
@ -685,6 +692,32 @@ class TestFileTiff:
assert description[0]["format"] == "image/tiff"
assert description[3]["BitsPerSample"]["Seq"]["li"] == ["8", "8", "8"]
def test_get_photoshop_blocks(self):
with Image.open("Tests/images/lab.tif") as im:
assert list(im.get_photoshop_blocks().keys()) == [
1061,
1002,
1005,
1062,
1037,
1049,
1011,
1034,
10000,
1013,
1016,
1032,
1054,
1050,
1064,
1041,
1044,
1036,
1057,
4000,
4001,
]
def test_close_on_load_exclusive(self, tmp_path):
# similar to test_fd_leak, but runs on unixlike os
tmpfile = str(tmp_path / "temp.tif")

View File

@ -1,8 +1,9 @@
import pytest
from packaging.version import parse as parse_version
from PIL import Image
from PIL import Image, features
from .helper import assert_image_similar, hopper, is_ppc64le
from .helper import assert_image_similar, hopper, is_ppc64le, skip_unless_feature
def test_sanity():
@ -17,16 +18,14 @@ def test_sanity():
assert_image_similar(converted.convert("RGB"), image, 60)
@pytest.mark.xfail(is_ppc64le(), reason="failing on ppc64le on GHA")
@skip_unless_feature("libimagequant")
def test_libimagequant_quantize():
image = hopper()
try:
converted = image.quantize(100, Image.Quantize.LIBIMAGEQUANT)
except ValueError as ex: # pragma: no cover
if "dependency" in str(ex).lower():
pytest.skip("libimagequant support not available")
else:
raise
if is_ppc64le():
libimagequant = parse_version(features.version_feature("libimagequant"))
if libimagequant < parse_version("4"):
pytest.skip("Fails with libimagequant earlier than 4.0.0 on ppc64le")
converted = image.quantize(100, Image.Quantize.LIBIMAGEQUANT)
assert converted.mode == "P"
assert_image_similar(converted.convert("RGB"), image, 15)
assert len(converted.getcolors()) == 100

View File

@ -0,0 +1,56 @@
9.1.0
-----
API Changes
===========
Raise an error when performing a negative crop
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Performing a negative crop on an image previously just returned a ``(0, 0)`` image. Now
it will raise a ``ValueError``, to help reduce confusion if a user has unintentionally
provided the wrong arguments.
Added specific error if path coordinate type is incorrect
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Rather than returning a ``SystemError``, passing the incorrect types of coordinates into
a path will now raise a more specific ``ValueError``, with the message "incorrect
coordinate type".
Deprecations
^^^^^^^^^^^^
ImageShow.Viewer.show_file file argument
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``file`` argument in :py:meth:`~PIL.ImageShow.Viewer.show_file()` has been
deprecated, replaced by ``path``.
In effect, ``viewer.show_file("test.jpg")`` will continue to work unchanged.
``viewer.show_file(file="test.jpg")`` will raise a deprecation warning, and suggest
``viewer.show_file(path="test.jpg")`` instead.
API Additions
=============
Added get_photoshop_blocks() to parse Photoshop TIFF tag
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
:py:meth:`~PIL.TiffImagePlugin.TiffImageFile.get_photoshop_blocks` has been added, to
allow users to determine what Photoshop "Image Resource Blocks" are contained within an
image. The keys of the returned dictionary are the image resource IDs.
At present, the information within each block is merely returned as a dictionary with a
"data" entry. This will allow more useful information to be added in the future without
breaking backwards compatibility.
Other Changes
=============
Image._repr_pretty_
^^^^^^^^^^^^^^^^^^^
``im._repr_pretty_`` has been added to provide a representation of an image without the
identity of the object. This allows Jupyter to describe an image and have that
description stay the same on subsequent executions of the same code.

View File

@ -14,6 +14,7 @@ expected to be backported to earlier versions.
.. toctree::
:maxdepth: 2
9.1.0
9.0.1
9.0.0
8.4.0

View File

@ -41,6 +41,7 @@
import io
import itertools
import logging
import math
import os
import struct
import warnings
@ -49,6 +50,8 @@ from fractions import Fraction
from numbers import Number, Rational
from . import Image, ImageFile, ImageOps, ImagePalette, TiffTags
from ._binary import i16be as i16
from ._binary import i32be as i32
from ._binary import o8
from .TiffTags import TYPES
@ -1129,6 +1132,27 @@ class TiffImageFile(ImageFile.ImageFile):
"""
return self._getxmp(self.tag_v2[700]) if 700 in self.tag_v2 else {}
def get_photoshop_blocks(self):
"""
Returns a dictionary of Photoshop "Image Resource Blocks".
The keys are the image resource ID. For more information, see
https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_pgfId-1037727
:returns: Photoshop "Image Resource Blocks" in a dictionary.
"""
blocks = {}
val = self.tag_v2.get(0x8649)
if val:
while val[:4] == b"8BIM":
id = i16(val[4:6])
n = math.ceil((val[6] + 1) / 2) * 2
size = i32(val[6 + n : 10 + n])
data = val[10 + n : 10 + n + size]
blocks[id] = {"data": data}
val = val[math.ceil((10 + n + size) / 2) * 2 :]
return blocks
def load(self):
if self.tile and self.use_load_libtiff:
return self._load_libtiff()
@ -1308,9 +1332,14 @@ class TiffImageFile(ImageFile.ImageFile):
else:
bps_count = 1
bps_count += len(extra_tuple)
# Some files have only one value in bps_tuple,
# while should have more. Fix it
if bps_count > len(bps_tuple) and len(bps_tuple) == 1:
bps_actual_count = len(bps_tuple)
if bps_count < bps_actual_count:
# If a file has more values in bps_tuple than expected,
# remove the excess.
bps_tuple = bps_tuple[:bps_count]
elif bps_count > bps_actual_count and bps_actual_count == 1:
# If a file has only one value in bps_tuple, when it should have more,
# presume it is the same number of bits for all of the samples.
bps_tuple = bps_tuple * bps_count
samplesPerPixel = self.tag_v2.get(

View File

@ -1216,9 +1216,7 @@ frompalette(Imaging imOut, Imaging imIn, const char *mode) {
convert = alpha ? pa2f : p2f;
} else if (strcmp(mode, "RGB") == 0) {
convert = alpha ? pa2rgb : p2rgb;
} else if (strcmp(mode, "RGBA") == 0) {
convert = alpha ? pa2rgba : p2rgba;
} else if (strcmp(mode, "RGBX") == 0) {
} else if (strcmp(mode, "RGBA") == 0 || strcmp(mode, "RGBX") == 0) {
convert = alpha ? pa2rgba : p2rgba;
} else if (strcmp(mode, "CMYK") == 0) {
convert = alpha ? pa2cmyk : p2cmyk;

View File

@ -280,9 +280,9 @@ deps = {
"libs": [r"imagequant.lib"],
},
"harfbuzz": {
"url": "https://github.com/harfbuzz/harfbuzz/archive/3.3.2.zip",
"filename": "harfbuzz-3.3.2.zip",
"dir": "harfbuzz-3.3.2",
"url": "https://github.com/harfbuzz/harfbuzz/archive/3.4.0.zip",
"filename": "harfbuzz-3.4.0.zip",
"dir": "harfbuzz-3.4.0",
"build": [
cmd_cmake("-DHB_HAVE_FREETYPE:BOOL=TRUE"),
cmd_nmake(target="clean"),