Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using getxmp from Pillow(min Pillow 8.3.0) #55

Merged
merged 3 commits into from
Nov 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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