Handle XMP data from an UNDEFINED TIFF tag (#8997)

This commit is contained in:
Hugo van Kemenade 2025-06-10 14:57:15 +03:00 committed by GitHub
commit de053fbae0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 30 additions and 3 deletions

View File

@ -14,6 +14,7 @@ from PIL import (
ImageFile, ImageFile,
JpegImagePlugin, JpegImagePlugin,
TiffImagePlugin, TiffImagePlugin,
TiffTags,
UnidentifiedImageError, UnidentifiedImageError,
) )
from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION from PIL.TiffImagePlugin import RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION
@ -900,6 +901,29 @@ class TestFileTiff:
assert description[0]["format"] == "image/tiff" assert description[0]["format"] == "image/tiff"
assert description[3]["BitsPerSample"]["Seq"]["li"] == ["8", "8", "8"] assert description[3]["BitsPerSample"]["Seq"]["li"] == ["8", "8", "8"]
def test_getxmp_undefined(self, tmp_path: Path) -> None:
tmpfile = tmp_path / "temp.tif"
im = Image.new("L", (1, 1))
ifd = TiffImagePlugin.ImageFileDirectory_v2()
ifd.tagtype[700] = TiffTags.UNDEFINED
with Image.open("Tests/images/lab.tif") as im_xmp:
ifd[700] = im_xmp.info["xmp"]
im.save(tmpfile, tiffinfo=ifd)
with Image.open(tmpfile) as im_reloaded:
if ElementTree is None:
with pytest.warns(
UserWarning,
match="XMP data cannot be read without defusedxml dependency",
):
assert im_reloaded.getxmp() == {}
else:
assert "xmp" in im_reloaded.info
xmp = im_reloaded.getxmp()
description = xmp["xmpmeta"]["RDF"]["Description"]
assert description[0]["format"] == "image/tiff"
def test_get_photoshop_blocks(self) -> None: def test_get_photoshop_blocks(self) -> None:
with Image.open("Tests/images/lab.tif") as im: with Image.open("Tests/images/lab.tif") as im:
assert isinstance(im, TiffImagePlugin.TiffImageFile) assert isinstance(im, TiffImagePlugin.TiffImageFile)

View File

@ -995,7 +995,7 @@ class TestImage:
im = Image.new("RGB", (1, 1)) im = Image.new("RGB", (1, 1))
im.info["xmp"] = ( im.info["xmp"] = (
b'<?xpacket begin="\xef\xbb\xbf" id="W5M0MpCehiHzreSzNTczkc9d"?>\n' b'<?xpacket begin="\xef\xbb\xbf" id="W5M0MpCehiHzreSzNTczkc9d"?>\n'
b'<x:xmpmeta xmlns:x="adobe:ns:meta/" />\n<?xpacket end="w"?>\x00\x00' b'<x:xmpmeta xmlns:x="adobe:ns:meta/" />\n<?xpacket end="w"?>\x00\x00 '
) )
if ElementTree is None: if ElementTree is None:
with pytest.warns( with pytest.warns(

View File

@ -1511,7 +1511,7 @@ class Image:
return {} return {}
if "xmp" not in self.info: if "xmp" not in self.info:
return {} return {}
root = ElementTree.fromstring(self.info["xmp"].rstrip(b"\x00")) root = ElementTree.fromstring(self.info["xmp"].rstrip(b"\x00 "))
return {get_name(root.tag): get_value(root)} return {get_name(root.tag): get_value(root)}
def getexif(self) -> Exif: def getexif(self) -> Exif:

View File

@ -1260,7 +1260,10 @@ class TiffImageFile(ImageFile.ImageFile):
self.fp.seek(self._frame_pos[frame]) self.fp.seek(self._frame_pos[frame])
self.tag_v2.load(self.fp) self.tag_v2.load(self.fp)
if XMP in self.tag_v2: if XMP in self.tag_v2:
self.info["xmp"] = self.tag_v2[XMP] xmp = self.tag_v2[XMP]
if isinstance(xmp, tuple) and len(xmp) == 1:
xmp = xmp[0]
self.info["xmp"] = xmp
elif "xmp" in self.info: elif "xmp" in self.info:
del self.info["xmp"] del self.info["xmp"]
self._reload_exif() self._reload_exif()