Skip to content

Commit 02d55b7

Browse files
authored
Merge pull request #4560 from radarhere/xmp
2 parents b8bc307 + f218169 commit 02d55b7

4 files changed

Lines changed: 42 additions & 20 deletions

File tree

171 KB
Loading

Tests/test_file_png.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -591,18 +591,27 @@ def test_textual_chunks_after_idat(self):
591591
with Image.open("Tests/images/hopper_idat_after_image_end.png") as im:
592592
assert im.text == {"TXT": "VALUE", "ZIP": "VALUE"}
593593

594-
@pytest.mark.parametrize(
595-
"test_file",
596-
[
597-
"Tests/images/exif.png", # With an EXIF chunk
598-
"Tests/images/exif_imagemagick.png", # With an ImageMagick zTXt chunk
599-
],
600-
)
601-
def test_exif(self, test_file):
602-
with Image.open(test_file) as im:
594+
def test_exif(self):
595+
# With an EXIF chunk
596+
with Image.open("Tests/images/exif.png") as im:
603597
exif = im._getexif()
604598
assert exif[274] == 1
605599

600+
# With an ImageMagick zTXt chunk
601+
with Image.open("Tests/images/exif_imagemagick.png") as im:
602+
exif = im._getexif()
603+
assert exif[274] == 1
604+
605+
# Assert that info still can be extracted
606+
# when the image is no longer a PngImageFile instance
607+
exif = im.copy().getexif()
608+
assert exif[274] == 1
609+
610+
# With XMP tags
611+
with Image.open("Tests/images/xmp_tags_orientation.png") as im:
612+
exif = im.getexif()
613+
assert exif[274] == 3
614+
606615
def test_exif_save(self, tmp_path):
607616
with Image.open("Tests/images/exif.png") as im:
608617
test_file = str(tmp_path / "temp.png")

src/PIL/Image.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import sys
3636
import tempfile
3737
import warnings
38+
import xml.etree.ElementTree
3839
from collections.abc import Callable, MutableMapping
3940
from pathlib import Path
4041

@@ -1300,7 +1301,28 @@ def getextrema(self):
13001301
def getexif(self):
13011302
if self._exif is None:
13021303
self._exif = Exif()
1303-
self._exif.load(self.info.get("exif"))
1304+
1305+
exif_info = self.info.get("exif")
1306+
if exif_info is None and "Raw profile type exif" in self.info:
1307+
exif_info = bytes.fromhex(
1308+
"".join(self.info["Raw profile type exif"].split("\n")[3:])
1309+
)
1310+
self._exif.load(exif_info)
1311+
1312+
# XMP tags
1313+
if 0x0112 not in self._exif:
1314+
xmp_tags = self.info.get("XML:com.adobe.xmp")
1315+
if xmp_tags:
1316+
root = xml.etree.ElementTree.fromstring(xmp_tags)
1317+
for elem in root.iter():
1318+
if elem.tag.endswith("}Description"):
1319+
orientation = elem.attrib.get(
1320+
"{http://ns.adobe.com/tiff/1.0/}Orientation"
1321+
)
1322+
if orientation:
1323+
self._exif[0x0112] = int(orientation)
1324+
break
1325+
13041326
return self._exif
13051327

13061328
def getim(self):

src/PIL/PngImagePlugin.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -931,16 +931,7 @@ def getexif(self):
931931
if "exif" not in self.info:
932932
self.load()
933933

934-
if self._exif is None:
935-
self._exif = Image.Exif()
936-
937-
exif_info = self.info.get("exif")
938-
if exif_info is None and "Raw profile type exif" in self.info:
939-
exif_info = bytes.fromhex(
940-
"".join(self.info["Raw profile type exif"].split("\n")[3:])
941-
)
942-
self._exif.load(exif_info)
943-
return self._exif
934+
return super().getexif()
944935

945936
def _close__fp(self):
946937
try:

0 commit comments

Comments
 (0)