diff --git a/pyproject.toml b/pyproject.toml index a4869612..83d3783d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ dependencies = [ dynamic = ["version"] [project.optional-dependencies] -all = ["brotli", "feedgenerator", "zopfli", "cryptography"] +all = ["brotli", "feedgenerator", "zopfli", "cryptography", "pillow-heif"] tests = ["pytest", "pytest-cov"] docs = ["Sphinx>=4.1.0", "furo", "cryptography"] diff --git a/src/sigal/gallery.py b/src/sigal/gallery.py index 51cb5d71..8ca5e010 100644 --- a/src/sigal/gallery.py +++ b/src/sigal/gallery.py @@ -264,7 +264,7 @@ def exif(self): datetime_format = self.settings["datetime_format"] return ( get_exif_tags(self.raw_exif, datetime_format=datetime_format) - if self.raw_exif and self.src_ext in (".jpg", ".jpeg") + if self.raw_exif and self.src_ext in (".jpg", ".jpeg", ".heic") else None ) @@ -289,7 +289,7 @@ def _get_markdown_metadata(self): @cached_property def raw_exif(self): """If not `None`, contains the raw EXIF tags.""" - if self.src_ext in (".jpg", ".jpeg"): + if self.src_ext in (".jpg", ".jpeg", ".heic"): return self.file_metadata["exif"] @cached_property diff --git a/src/sigal/image.py b/src/sigal/image.py index 83a994ae..4996125d 100644 --- a/src/sigal/image.py +++ b/src/sigal/image.py @@ -44,6 +44,11 @@ from pilkit.processors import Transpose from pilkit.utils import save_image +try: + from pillow_heif import HeifImagePlugin +except: + pass + from . import signals, utils # Force loading of truncated files @@ -220,7 +225,10 @@ def get_exif_data(filename): try: with warnings.catch_warnings(record=True) as caught_warnings: - exif = img._getexif() or {} + exif = {} + exifdata = img.getexif() + if exifdata: + exif = exifdata._get_merged_dict() except ZeroDivisionError: logger.warning("Failed to read EXIF data.") return None @@ -290,7 +298,7 @@ def get_image_metadata(filename): logger.error("Could not open image %s metadata: %s", filename, e) else: try: - if os.path.splitext(filename)[1].lower() in (".jpg", ".jpeg"): + if os.path.splitext(filename)[1].lower() in (".jpg", ".jpeg", ".heic"): exif = get_exif_data(img) except Exception as e: logger.warning("Could not read EXIF data from %s: %s", filename, e) diff --git a/tests/sample/pictures/dir1/test1/outdoor.heic b/tests/sample/pictures/dir1/test1/outdoor.heic new file mode 100644 index 00000000..2632594c Binary files /dev/null and b/tests/sample/pictures/dir1/test1/outdoor.heic differ diff --git a/tests/test_image.py b/tests/test_image.py index 133ca516..34298aad 100644 --- a/tests/test_image.py +++ b/tests/test_image.py @@ -201,6 +201,15 @@ def test_get_exif_tags(): assert "datetime" not in simple assert "gps" not in simple +def test_get_heic_exif_tags(): + test_image = "outdoor.heic" + src_file = os.path.join( + CURRENT_DIR, "sample", "pictures", "dir1", "test1", test_image + ) + data = get_exif_data(src_file) + simple = get_exif_tags(data, datetime_format="%d/%m/%Y") + assert simple["Make"] == "samsung" + assert simple["datetime"] == "01/09/2024" def test_get_iptc_data(caplog): test_image = "1.jpg"