Skip to content

Commit

Permalink
Using getxmp from Pillow(min Pillow 8.3.0) (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
bigcat88 authored Nov 26, 2022
1 parent b022a1d commit 4586e7c
Show file tree
Hide file tree
Showing 9 changed files with 16 additions and 76 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/analysis-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ jobs:
- name: Install from source
run: |
python -m pip install opencv-python coverage pillow==8.1.0
python -m pip install opencv-python coverage pillow==8.4.0
python -m pip -v install ".[tests]"
- name: LibHeif info
Expand Down
2 changes: 1 addition & 1 deletion pi-heif/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ zip_safe = False
packages = find:
install_requires =
cffi>=1.14.6
pillow>=6.2.0
pillow>=8.3.0

[options.extras_require]
tests =
Expand Down
2 changes: 1 addition & 1 deletion pillow_heif/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@
open_heif,
read_heif,
)
from .misc import get_file_mimetype, getxmp, set_orientation
from .misc import get_file_mimetype, set_orientation
from .thumbnails import add_thumbnails, thumbnail
8 changes: 6 additions & 2 deletions pillow_heif/as_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from .constants import HeifCompressionFormat, HeifErrorCode
from .error import HeifError
from .heif import HeifFile, open_heif
from .misc import _get_bytes, getxmp, set_orientation
from .misc import _get_bytes, set_orientation


class _LibHeifImageFile(ImageFile.ImageFile):
Expand Down Expand Up @@ -61,7 +61,11 @@ def getxmp(self) -> dict:
:returns: XMP tags in a dictionary."""

return getxmp(self.info["xmp"])
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
50 changes: 0 additions & 50 deletions pillow_heif/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,6 @@
import re
from struct import pack, unpack
from typing import Union
from warnings import warn

try:
from defusedxml import ElementTree
except ImportError:
ElementTree = None


def set_orientation(info: dict, orientation: int = 1) -> Union[int, None]:
Expand Down Expand Up @@ -106,47 +100,3 @@ def _get_bytes(fp, length=None) -> bytes:
fp.seek(offset)
return result
return bytes(fp)[:length]


def getxmp(xmp_data: bytes) -> dict:
"""Returns a dictionary containing the XMP tags.
**Requires defusedxml to be installed.** Implementation taken from ``Pillow``.
Used in :py:meth:`pillow_heif.as_opener._LibHeifImageFile.getxmp` by Pillow plugins.
:param xmp_data: ``bytes`` containing string in UTF-8 encoding with XMP tags.
:returns: XMP tags in a dictionary."""

def get_name(tag):
return tag.split("}")[1]

def get_value(element):
value = {get_name(k): v for k, v in element.attrib.items()}
children = list(element)
if children:
for child in children:
name = get_name(child.tag)
child_value = get_value(child)
if name in value:
if not isinstance(value[name], list):
value[name] = [value[name]]
value[name].append(child_value)
else:
value[name] = child_value
elif value:
if element.text:
value["text"] = element.text
else:
return element.text
return value

if xmp_data:
if ElementTree is None:
warn("XMP data cannot be read without defusedxml dependency")
return {}
_clear_data = xmp_data.rsplit(b"\x00", 1)
if _clear_data[0]:
root = ElementTree.fromstring(_clear_data[0])
return {get_name(root.tag): get_value(root)}
return {}
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ zip_safe = False
packages = find:
install_requires =
cffi>=1.14.6
pillow>=6.2.0
pillow>=8.3.0

[options.extras_require]
docs =
Expand Down
14 changes: 6 additions & 8 deletions tests/metadata_xmp_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@

import helpers
import pytest
from packaging.version import parse as parse_version
from PIL import Image
from PIL import __version__ as pil_version
from PIL import features
from PIL import Image, features

import pillow_heif

pytest.importorskip("defusedxml", reason="defusedxml not installed")

os.chdir(os.path.dirname(os.path.abspath(__file__)))
pillow_heif.register_avif_opener()
pillow_heif.register_heif_opener()
Expand All @@ -19,7 +18,6 @@
@pytest.mark.skipif(not features.check("webp"), reason="Requires WEBP support.")
@pytest.mark.skipif(not helpers.aom_enc(), reason="Requires AVIF encoder.")
@pytest.mark.skipif(not helpers.hevc_enc(), reason="Requires HEVC encoder.")
@pytest.mark.skipif(parse_version(pil_version) < parse_version("8.3.0"), reason="Requires Pillow >= 8.3")
@pytest.mark.parametrize("save_format", ("HEIF", "AVIF"))
@pytest.mark.parametrize(
"img_path",
Expand All @@ -32,9 +30,9 @@
)
def test_xmp_from_pillow(img_path, save_format):
im = Image.open(Path(img_path))
xmp = im.getxmp() if hasattr(im, "getxmp") else pillow_heif.getxmp(im.info["xmp"]) # noqa
pytest.importorskip("defusedxml", reason="requires `defusedxml`")
assert xmp["xmpmeta"]["RDF"]["Description"]["subject"]["Bag"]["li"] == "TestSubject"
if hasattr(im, "getxmp"): # WebP do not have `getxmp` method(Pillow <=9.3.0)
xmp = im.getxmp() # noqa
assert xmp["xmpmeta"]["RDF"]["Description"]["subject"]["Bag"]["li"] == "TestSubject"
out_im_heif = BytesIO()
im.save(out_im_heif, format=save_format)
im_heif = Image.open(out_im_heif)
Expand Down
5 changes: 0 additions & 5 deletions tests/orientation_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

import pytest
from helpers import assert_image_similar, hevc_enc
from packaging.version import parse as parse_version
from PIL import Image, ImageOps
from PIL import __version__ as pil_version

import pillow_heif

Expand Down Expand Up @@ -43,7 +41,6 @@ def get_xmp_with_orientation(orientation: int, style=1) -> str:


@pytest.mark.skipif(not hevc_enc(), reason="Requires HEVC encoder.")
@pytest.mark.skipif(parse_version(pil_version) < parse_version("8.3.0"), reason="Requires Pillow >= 8.3")
@pytest.mark.parametrize("orientation", (1, 2, 3, 4, 5, 6, 7, 8))
@pytest.mark.parametrize("im_format", ("JPEG", "PNG"))
def test_exif_orientation(orientation, im_format):
Expand All @@ -68,7 +65,6 @@ def test_exif_orientation(orientation, im_format):
assert_image_similar(im, im_heif)


@pytest.mark.skipif(parse_version(pil_version) < parse_version("8.3.0"), reason="Requires Pillow >= 8.3")
@pytest.mark.parametrize("orientation", (1, 2, 3, 4, 5, 6, 7, 8))
def test_png_xmp_orientation(orientation):
im = Image.effect_mandelbrot((256, 128), (-3, -2.5, 2, 2.5), 100).crop((0, 0, 256, 96))
Expand Down Expand Up @@ -161,7 +157,6 @@ def test_heif_xmp_orientation_with_exif_eq_1(orientation):


@pytest.mark.skipif(not hevc_enc(), reason="Requires HEVC encoder.")
@pytest.mark.skipif(parse_version(pil_version) < parse_version("8.3.0"), reason="Requires Pillow >= 8.3")
@pytest.mark.parametrize("orientation", (1, 2))
@pytest.mark.parametrize("im_format", ("JPEG", "PNG"))
def test_exif_heif_exif_orientation(orientation, im_format):
Expand Down
7 changes: 0 additions & 7 deletions tests/read_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,6 @@ def test_heif_read_images(image_path):
def test_read_image(convert_hdr_to_8bit: bool) -> bool:
heif_file = pillow_heif.open_heif(image_path, convert_hdr_to_8bit=convert_hdr_to_8bit)
for image in heif_file:
assert isinstance(pillow_heif.getxmp(image.info["xmp"]), dict)
assert min(image.size) > 0
assumed_mode = "RGBA" if image.has_alpha else "RGB"
if image.bit_depth > 8:
Expand Down Expand Up @@ -296,12 +295,6 @@ def test_heif_index():
del heif_file[len(heif_file)]


@mock.patch("pillow_heif.misc.ElementTree", None)
def test_no_defusedxml(monkeypatch):
with pytest.warns(UserWarning):
pillow_heif.getxmp(b"xmp_data")


def test_read_heif():
heif_file = pillow_heif.read_heif(Path("images/heif/zPug_3.heic"))
for im in heif_file:
Expand Down

0 comments on commit 4586e7c

Please sign in to comment.