Skip to content

Commit

Permalink
do not set empty xmp in the im.info dict (#254)
Browse files Browse the repository at this point in the history
* do not set empty `xmp` in the `im.info` dict

Signed-off-by: Alexander Piskun <bigcat88@icloud.com>

---------

Signed-off-by: Alexander Piskun <bigcat88@icloud.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
bigcat88 and pre-commit-ci[bot] committed Jun 27, 2024
1 parent aeda972 commit c01496e
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 22 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ All notable changes to this project will be documented in this file.

## [0.17.0 - 2024-07-02]

### Added

- Support for `Pillow` **10.4.0** #254

### Changed

- Minimum supported Pillow version raised to `10.1.0`. #251
- `xmp` in `info` dictionary is not present if it is empty. #254

### Fixed

Expand Down
4 changes: 2 additions & 2 deletions docs/pillow-plugin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ Removing EXIF and XMP information inside ``info`` dictionary:
.. code-block:: python
image = Image.open(Path("test.heic"))
image.info["exif"] = None
image.info["xmp"] = None
del image.info["exif"]
del image.info["xmp"]
image.save("output.heic")
Removing EXIF and XMP specifying them when calling ``save``:
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/HeifImage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ HeifImage object
.. py:attribute:: info["xmp"]
:type: bytes

XMP metadata. String in bytes in UTF-8 encoding. Can be `None`
XMP metadata. String in bytes in UTF-8 encoding. Absent if `xmp` data is missing.

.. py:attribute:: info["metadata"]
:type: list[dict]
Expand Down
21 changes: 12 additions & 9 deletions pillow_heif/as_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from warnings import warn

from PIL import Image, ImageFile, ImageSequence
from PIL import __version__ as pil_version

from . import options
from .constants import HeifCompressionFormat
Expand Down Expand Up @@ -71,16 +72,18 @@ def load(self):
self._heif_file = None
return super().load()

def getxmp(self) -> dict:
"""Returns a dictionary containing the XMP tags. Requires ``defusedxml`` to be installed.
if pil_version[:4] in ("10.1", "10.2", "10.3"):

:returns: XMP tags in a dictionary.
"""
if self.info.get("xmp", None):
xmp_data = self.info["xmp"].rsplit(b"\x00", 1)
if xmp_data[0]:
return self._getxmp(xmp_data[0])
return {}
def getxmp(self) -> dict:
"""Returns a dictionary containing the XMP tags. Requires ``defusedxml`` to be installed.
:returns: XMP tags in a dictionary.
"""
if self.info.get("xmp", None):
xmp_data = self.info["xmp"].rsplit(b"\x00", 1)
if xmp_data[0]:
return self._getxmp(xmp_data[0])
return {}

def seek(self, frame):
if not self._seek_check(frame):
Expand Down
11 changes: 8 additions & 3 deletions pillow_heif/heif.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,12 @@ def __init__(self, c_image):
"primary": bool(c_image.primary),
"bit_depth": int(c_image.bit_depth),
"exif": _exif,
"xmp": _xmp,
"metadata": _metadata,
"thumbnails": _thumbnails,
"depth_images": _depth_images,
}
if _xmp:
self.info["xmp"] = _xmp
save_colorspace_chroma(c_image, self.info)
_color_profile: Dict[str, Any] = c_image.color_profile
if _color_profile:
Expand Down Expand Up @@ -424,7 +425,9 @@ def add_from_pillow(self, image: Image.Image) -> HeifImage:
raise ValueError("Empty images are not supported.")
_info = image.info.copy()
_info["exif"] = _exif_from_pillow(image)
_info["xmp"] = _xmp_from_pillow(image)
_xmp = _xmp_from_pillow(image)
if _xmp:
_info["xmp"] = _xmp
original_orientation = set_orientation(_info)
_img = _pil_to_supported_mode(image)
if original_orientation is not None and original_orientation != 1:
Expand All @@ -442,7 +445,9 @@ def add_from_pillow(self, image: Image.Image) -> HeifImage:
if key in image.info:
added_image.info[key] = deepcopy(image.info[key])
added_image.info["exif"] = _exif_from_pillow(image)
added_image.info["xmp"] = _xmp_from_pillow(image)
_xmp = _xmp_from_pillow(image)
if _xmp:
added_image.info["xmp"] = _xmp
return added_image

@property
Expand Down
5 changes: 4 additions & 1 deletion tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ def compare_images_fields(image1: HeifImage, image2: HeifImage):
difference = box - image2.info["thumbnails"][i2]
assert abs(difference) <= thumb_size_max_differ
assert image1.info["exif"] == image2.info["exif"]
assert image1.info["xmp"] == image2.info["xmp"]
if "xmp" in image1.info:
assert image1.info["xmp"] == image2.info["xmp"]
else:
assert "xmp" not in image2.info
for block_i, block in enumerate(image1.info["metadata"]):
assert block["data"] == image1.info["metadata"][block_i]["data"]
assert block["content_type"] == image1.info["metadata"][block_i]["content_type"]
Expand Down
12 changes: 6 additions & 6 deletions tests/metadata_etc_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ def test_heif_info_changing(save_format):
im_out = pillow_heif.open_heif(out_buf)
for i in range(3):
if i == 1:
assert im_out[i].info["primary"] and not im_out[i].info["exif"] and not im_out[i].info["xmp"]
assert im_out[i].info["primary"] and not im_out[i].info["exif"] and "xmp" not in im_out[i].info
else:
assert not im_out[i].info["primary"] and not im_out[i].info["exif"] and not im_out[i].info["xmp"]
assert not im_out[i].info["primary"] and not im_out[i].info["exif"] and "xmp" not in im_out[i].info
# Set exif and xmp of all images. Change Primary Image to be last.
for i in range(3):
im[i].info["xmp"] = xmp
Expand All @@ -110,7 +110,7 @@ def test_heif_info_changing(save_format):
assert im_out.info["primary"]
assert im_out.primary_index == 0
for i in range(3):
assert not im_out[i].info["exif"] and not im_out[i].info["xmp"]
assert not im_out[i].info["exif"] and "xmp" not in im_out[i].info


@pytest.mark.skipif(not aom(), reason="Requires AVIF support.")
Expand All @@ -136,9 +136,9 @@ def test_pillow_info_changing(save_format):
for i in range(3):
im_out.seek(i)
if i == 1:
assert im_out.info["primary"] and not im_out.info["exif"] and not im_out.info["xmp"]
assert im_out.info["primary"] and not im_out.info["exif"] and "xmp" not in im_out.info
else:
assert not im_out.info["primary"] and not im_out.info["exif"] and not im_out.info["xmp"]
assert not im_out.info["primary"] and not im_out.info["exif"] and "xmp" not in im_out.info
# Set exif and xmp of all images. Change Primary Image to be last.
for i in range(3):
im.seek(i)
Expand All @@ -164,7 +164,7 @@ def test_pillow_info_changing(save_format):
assert im_out.tell() == 0
for i in range(3):
im_out.seek(i)
assert not im_out.info["exif"] and not im_out.info["xmp"]
assert not im_out.info["exif"] and "xmp" not in im_out.info


@pytest.mark.skipif(not aom(), reason="Requires AVIF support.")
Expand Down

0 comments on commit c01496e

Please sign in to comment.