Merge branch 'master' into rm-3.5

This commit is contained in:
Hugo van Kemenade 2020-09-02 20:36:30 +03:00 committed by GitHub
commit ddc4c64664
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 65 additions and 27 deletions

View File

@ -5,6 +5,9 @@ Changelog (Pillow)
8.0.0 (unreleased) 8.0.0 (unreleased)
------------------ ------------------
- Added writing of subIFDs #4862
[radarhere]
- Fix IFDRational __eq__ bug #4888 - Fix IFDRational __eq__ bug #4888
[luphord, radarhere] [luphord, radarhere]

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -8,6 +8,7 @@ from PIL import (
ExifTags, ExifTags,
Image, Image,
ImageFile, ImageFile,
ImageOps,
JpegImagePlugin, JpegImagePlugin,
UnidentifiedImageError, UnidentifiedImageError,
features, features,
@ -225,23 +226,48 @@ class TestFileJpeg:
# Should not raise a TypeError # Should not raise a TypeError
im._getexif() im._getexif()
def test_exif_gps(self): def test_exif_gps(self, tmp_path):
# Arrange expected_exif_gps = {
0: b"\x00\x00\x00\x01",
2: 4294967295,
5: b"\x01",
30: 65535,
29: "1999:99:99 99:99:99",
}
gps_index = 34853
# Reading
with Image.open("Tests/images/exif_gps.jpg") as im: with Image.open("Tests/images/exif_gps.jpg") as im:
gps_index = 34853
expected_exif_gps = {
0: b"\x00\x00\x00\x01",
2: 4294967295,
5: b"\x01",
30: 65535,
29: "1999:99:99 99:99:99",
}
# Act
exif = im._getexif() exif = im._getexif()
assert exif[gps_index] == expected_exif_gps
# Assert # Writing
assert exif[gps_index] == expected_exif_gps f = str(tmp_path / "temp.jpg")
exif = Image.Exif()
exif[gps_index] = expected_exif_gps
hopper().save(f, exif=exif)
with Image.open(f) as reloaded:
exif = reloaded._getexif()
assert exif[gps_index] == expected_exif_gps
def test_empty_exif_gps(self):
with Image.open("Tests/images/empty_gps_ifd.jpg") as im:
exif = im.getexif()
del exif[0x8769]
# Assert that it needs to be transposed
assert exif[0x0112] == Image.TRANSVERSE
# Assert that the GPS IFD is present and empty
assert exif[0x8825] == {}
transposed = ImageOps.exif_transpose(im)
exif = transposed.getexif()
assert exif[0x8825] == {}
# Assert that it was transposed
assert 0x0112 not in exif
def test_exif_equality(self): def test_exif_equality(self):
# In 7.2.0, Exif rationals were changed to be read as # In 7.2.0, Exif rationals were changed to be read as

View File

@ -36,10 +36,4 @@ What about PIL?
Prior to Pillow 2.0.0, very few image code changes were made. Pillow 2.0.0 Prior to Pillow 2.0.0, very few image code changes were made. Pillow 2.0.0
added Python 3 support and includes many bug fixes from many contributors. added Python 3 support and includes many bug fixes from many contributors.
As more time passes since the last PIL release (1.1.7 in 2009), the likelihood of a new PIL release decreases. However, we've yet to hear an official "PIL is dead" announcement. So if you still want to support PIL, please `report issues here first`_, then `open corresponding Pillow tickets here`_. As more time passes since the last PIL release (1.1.7 in 2009), the likelihood of a new PIL release decreases. However, we've yet to hear an official "PIL is dead" announcement.
.. _report issues here first: https://bitbucket.org/effbot/pil-2009-raclette/issues
.. _open corresponding Pillow tickets here: https://github.com/python-pillow/Pillow/issues
Please provide a link to the first ticket so we can track the issue(s) upstream.

View File

@ -569,7 +569,9 @@ class ImageFileDirectory_v2(MutableMapping):
elif self.tagtype[tag] == TiffTags.RATIONAL: elif self.tagtype[tag] == TiffTags.RATIONAL:
values = [float(v) if isinstance(v, int) else v for v in values] values = [float(v) if isinstance(v, int) else v for v in values]
values = tuple(info.cvt_enum(value) for value in values) is_ifd = self.tagtype[tag] == TiffTags.LONG and isinstance(values, dict)
if not is_ifd:
values = tuple(info.cvt_enum(value) for value in values)
dest = self._tags_v1 if legacy_api else self._tags_v2 dest = self._tags_v1 if legacy_api else self._tags_v2
@ -578,7 +580,7 @@ class ImageFileDirectory_v2(MutableMapping):
# Spec'd length == 1, Actual > 1, Warn and truncate. Formerly barfed. # Spec'd length == 1, Actual > 1, Warn and truncate. Formerly barfed.
# No Spec, Actual length 1, Formerly (<4.2) returned a 1 element tuple. # No Spec, Actual length 1, Formerly (<4.2) returned a 1 element tuple.
# Don't mess with the legacy api, since it's frozen. # Don't mess with the legacy api, since it's frozen.
if ( if not is_ifd and (
(info.length == 1) (info.length == 1)
or self.tagtype[tag] == TiffTags.BYTE or self.tagtype[tag] == TiffTags.BYTE
or (info.length is None and len(values) == 1 and not legacy_api) or (info.length is None and len(values) == 1 and not legacy_api)
@ -804,11 +806,22 @@ class ImageFileDirectory_v2(MutableMapping):
stripoffsets = len(entries) stripoffsets = len(entries)
typ = self.tagtype.get(tag) typ = self.tagtype.get(tag)
logger.debug(f"Tag {tag}, Type: {typ}, Value: {value}") logger.debug(f"Tag {tag}, Type: {typ}, Value: {value}")
values = value if isinstance(value, tuple) else (value,) is_ifd = typ == TiffTags.LONG and isinstance(value, dict)
data = self._write_dispatch[typ](self, *values) if is_ifd:
if self._endian == "<":
ifh = b"II\x2A\x00\x08\x00\x00\x00"
else:
ifh = b"MM\x00\x2A\x00\x00\x00\x08"
ifd = ImageFileDirectory_v2(ifh)
for ifd_tag, ifd_value in self._tags_v2[tag].items():
ifd[ifd_tag] = ifd_value
data = ifd.tobytes(offset)
else:
values = value if isinstance(value, tuple) else (value,)
data = self._write_dispatch[typ](self, *values)
tagname = TiffTags.lookup(tag).name tagname = TiffTags.lookup(tag).name
typname = TYPES.get(typ, "unknown") typname = "ifd" if is_ifd else TYPES.get(typ, "unknown")
msg = f"save: {tagname} ({tag}) - type: {typname} ({typ})" msg = f"save: {tagname} ({tag}) - type: {typname} ({typ})"
msg += " - value: " + ( msg += " - value: " + (
"<table: %d bytes>" % len(data) if len(data) >= 16 else str(values) "<table: %d bytes>" % len(data) if len(data) >= 16 else str(values)
@ -816,7 +829,9 @@ class ImageFileDirectory_v2(MutableMapping):
logger.debug(msg) logger.debug(msg)
# count is sum of lengths for string and arbitrary data # count is sum of lengths for string and arbitrary data
if typ in [TiffTags.BYTE, TiffTags.ASCII, TiffTags.UNDEFINED]: if is_ifd:
count = 1
elif typ in [TiffTags.BYTE, TiffTags.ASCII, TiffTags.UNDEFINED]:
count = len(data) count = len(data)
else: else:
count = len(values) count = len(values)