Merge pull request #4862 from radarhere/subifds

This commit is contained in:
Hugo van Kemenade 2020-09-02 16:58:55 +03:00 committed by GitHub
commit 9f1f63a46b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 20 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -8,6 +8,7 @@ from PIL import (
ExifTags,
Image,
ImageFile,
ImageOps,
JpegImagePlugin,
UnidentifiedImageError,
features,
@ -225,23 +226,48 @@ class TestFileJpeg:
# Should not raise a TypeError
im._getexif()
def test_exif_gps(self):
# Arrange
def test_exif_gps(self, tmp_path):
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:
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()
assert exif[gps_index] == expected_exif_gps
# Assert
assert exif[gps_index] == expected_exif_gps
# Writing
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):
# In 7.2.0, Exif rationals were changed to be read as

View File

@ -569,7 +569,9 @@ class ImageFileDirectory_v2(MutableMapping):
elif self.tagtype[tag] == TiffTags.RATIONAL:
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
@ -578,7 +580,7 @@ class ImageFileDirectory_v2(MutableMapping):
# Spec'd length == 1, Actual > 1, Warn and truncate. Formerly barfed.
# No Spec, Actual length 1, Formerly (<4.2) returned a 1 element tuple.
# Don't mess with the legacy api, since it's frozen.
if (
if not is_ifd and (
(info.length == 1)
or self.tagtype[tag] == TiffTags.BYTE
or (info.length is None and len(values) == 1 and not legacy_api)
@ -804,11 +806,22 @@ class ImageFileDirectory_v2(MutableMapping):
stripoffsets = len(entries)
typ = self.tagtype.get(tag)
logger.debug("Tag {}, Type: {}, Value: {}".format(tag, typ, value))
values = value if isinstance(value, tuple) else (value,)
data = self._write_dispatch[typ](self, *values)
is_ifd = typ == TiffTags.LONG and isinstance(value, dict)
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
typname = TYPES.get(typ, "unknown")
typname = "ifd" if is_ifd else TYPES.get(typ, "unknown")
msg = "save: %s (%d) - type: %s (%d)" % (tagname, tag, typname, typ)
msg += " - value: " + (
"<table: %d bytes>" % len(data) if len(data) >= 16 else str(values)
@ -816,7 +829,9 @@ class ImageFileDirectory_v2(MutableMapping):
logger.debug(msg)
# 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)
else:
count = len(values)