Do not set info["exif"] to None

This commit is contained in:
Andrew Murray 2025-05-07 20:33:44 +10:00
parent 5e0457a2b3
commit 9266318048
2 changed files with 43 additions and 20 deletions

View File

@ -4,7 +4,7 @@ from types import ModuleType
import pytest import pytest
from PIL import Image from PIL import Image, JpegXlImagePlugin
from .helper import skip_unless_feature from .helper import skip_unless_feature
@ -73,25 +73,52 @@ def test_read_icc_profile() -> None:
def test_getxmp() -> None: def test_getxmp() -> None:
with Image.open("Tests/images/flower.jxl") as im: with Image.open("Tests/images/flower.jxl") as im:
assert "xmp" not in im.info assert "xmp" not in im.info
assert im.getxmp() == {} if ElementTree is None:
with pytest.warns(
UserWarning,
match="XMP data cannot be read without defusedxml dependency",
):
xmp = im.getxmp()
else:
xmp = im.getxmp()
assert xmp == {}
with Image.open("Tests/images/flower2.jxl") as im: with Image.open("Tests/images/flower2.jxl") as im:
if ElementTree: if ElementTree is None:
assert (
im.getxmp()["xmpmeta"]["xmptk"]
== "Adobe XMP Core 5.3-c011 66.145661, 2012/02/06-14:56:27 "
)
else:
with pytest.warns( with pytest.warns(
UserWarning, UserWarning,
match="XMP data cannot be read without defusedxml dependency", match="XMP data cannot be read without defusedxml dependency",
): ):
assert im.getxmp() == {} assert im.getxmp() == {}
else:
assert "xmp" in im.info
assert (
im.getxmp()["xmpmeta"]["xmptk"]
== "Adobe XMP Core 5.3-c011 66.145661, 2012/02/06-14:56:27 "
)
def test_4_byte_exif(monkeypatch: pytest.MonkeyPatch) -> None:
class _mock_jpegxl:
class PILJpegXlDecoder:
def __init__(self, b: bytes) -> None:
pass
def test_fix_exif_fail() -> None: def get_info(self) -> tuple[int, int, str, int, int, int, int, int]:
with Image.open("Tests/images/flower2.jxl") as image: return (1, 1, "L", 0, 0, 0, 0, 0)
assert image._fix_exif(b"\0\0\0\0") is None
def get_icc(self) -> None:
pass
def get_exif(self) -> None:
return b"\0\0\0\0"
def get_xmp(self) -> None:
pass
monkeypatch.setattr(JpegXlImagePlugin, "_jpegxl", _mock_jpegxl)
with Image.open("Tests/images/hopper.jxl") as image:
assert "exif" not in image.info
def test_read_exif_metadata_empty() -> None: def test_read_exif_metadata_empty() -> None:

View File

@ -67,20 +67,16 @@ class JpegXlImageFile(ImageFile.ImageFile):
if icc := self._decoder.get_icc(): if icc := self._decoder.get_icc():
self.info["icc_profile"] = icc self.info["icc_profile"] = icc
if exif := self._decoder.get_exif(): if exif := self._decoder.get_exif():
self.info["exif"] = self._fix_exif(exif) # jpeg xl does some weird shenanigans when storing exif
# it omits first 6 bytes of tiff header but adds 4 byte offset instead
if len(exif) > 4:
exif_start_offset = struct.unpack(">I", exif[:4])[0]
self.info["exif"] = exif[exif_start_offset + 4 :]
if xmp := self._decoder.get_xmp(): if xmp := self._decoder.get_xmp():
self.info["xmp"] = xmp self.info["xmp"] = xmp
self._rewind() self._rewind()
def _fix_exif(self, exif: bytes) -> bytes | None:
# jpeg xl does some weird shenanigans when storing exif
# it omits first 6 bytes of tiff header but adds 4 byte offset instead
if len(exif) <= 4:
return None
exif_start_offset = struct.unpack(">I", exif[:4])[0]
return exif[exif_start_offset + 4 :]
def _getexif(self) -> dict[int, Any] | None: def _getexif(self) -> dict[int, Any] | None:
if "exif" not in self.info: if "exif" not in self.info:
return None return None