Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Exif hide_offsets() #6762

Merged
merged 2 commits into from Dec 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 25 additions & 0 deletions Tests/test_image.py
Expand Up @@ -857,6 +857,31 @@ def test_exif_load_from_fp(self):
34665: 196,
}

def test_exif_hide_offsets(self):
with Image.open("Tests/images/flower.jpg") as im:
exif = im.getexif()

# Check offsets are present initially
assert 0x8769 in exif
for tag in (0xA005, 0x927C):
assert tag in exif.get_ifd(0x8769)
assert exif.get_ifd(0xA005)
loaded_exif = exif

with Image.open("Tests/images/flower.jpg") as im:
new_exif = im.getexif()

for exif in (loaded_exif, new_exif):
exif.hide_offsets()

# Assert they are hidden afterwards,
# but that the IFDs are still available
assert 0x8769 not in exif
assert exif.get_ifd(0x8769)
for tag in (0xA005, 0x927C):
assert tag not in exif.get_ifd(0x8769)
assert exif.get_ifd(0xA005)

@pytest.mark.parametrize("size", ((1, 0), (0, 1), (0, 0)))
def test_zero_tobytes(self, size):
im = Image.new("RGB", size)
Expand Down
23 changes: 20 additions & 3 deletions src/PIL/Image.py
Expand Up @@ -3552,6 +3552,7 @@ class Exif(MutableMapping):

def __init__(self):
self._data = {}
self._hidden_data = {}
self._ifds = {}
self._info = None
self._loaded_exif = None
Expand Down Expand Up @@ -3605,6 +3606,7 @@ def load(self, data):
return
self._loaded_exif = data
self._data.clear()
self._hidden_data.clear()
self._ifds.clear()
if data and data.startswith(b"Exif\x00\x00"):
data = data[6:]
Expand All @@ -3625,6 +3627,7 @@ def load(self, data):
def load_from_fp(self, fp, offset=None):
self._loaded_exif = None
self._data.clear()
self._hidden_data.clear()
self._ifds.clear()

# process dictionary
Expand Down Expand Up @@ -3687,8 +3690,9 @@ def get_ifd(self, tag):
if self._info is not None:
self._ifds[tag] = self._get_ifd_dict(self._info.next)
elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]:
if tag in self:
self._ifds[tag] = self._get_ifd_dict(self[tag])
offset = self._hidden_data.get(tag, self.get(tag))
if offset is not None:
self._ifds[tag] = self._get_ifd_dict(offset)
elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.Makernote]:
if ExifTags.IFD.Exif not in self._ifds:
self.get_ifd(ExifTags.IFD.Exif)
Expand Down Expand Up @@ -3771,7 +3775,20 @@ def get_ifd(self, tag):
else:
# Interop
self._ifds[tag] = self._get_ifd_dict(tag_data)
return self._ifds.get(tag, {})
ifd = self._ifds.get(tag, {})
if tag == ExifTags.IFD.Exif and self._hidden_data:
ifd = {
k: v
for (k, v) in ifd.items()
if k not in (ExifTags.IFD.Interop, ExifTags.IFD.Makernote)
}
return ifd

def hide_offsets(self):
for tag in (ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo):
if tag in self:
self._hidden_data[tag] = self[tag]
del self[tag]

def __str__(self):
if self._info is not None:
Expand Down