Compare commits
2 Commits
3075aaf595
...
5a6f29d957
Author | SHA1 | Date |
---|---|---|
Jean-Claude | 5a6f29d957 | |
Jean-Claude | a3f33e86c2 |
97
__init__.py
97
__init__.py
|
@ -1,18 +1,18 @@
|
|||
# vim: ft=python fileencoding=utf-8 sw=4 et sts=4
|
||||
|
||||
"""Utility functions and classes for exif handling.
|
||||
"""Metadata plugin based on gexiv2 (https://wiki.gnome.org/Projects/gexiv2) backend.
|
||||
|
||||
All exif related tasks are implemented in this module. The heavy lifting is done using
|
||||
one of the supported exif libraries, i.e.
|
||||
* piexif (https://pypi.org/project/piexif/) and
|
||||
* pyexiv2 (https://pypi.org/project/py3exiv2/).
|
||||
Properties:
|
||||
- Gnome dependencies.
|
||||
- Formatted Metadata.
|
||||
- Reads Exif, IPTC and XMP.
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
from typing import Any, Sequence, Iterable
|
||||
|
||||
from vimiv.imutils import exif
|
||||
from vimiv.utils import log, lazy, is_hex
|
||||
from vimiv.imutils import metadata
|
||||
from vimiv.utils import log, is_hex
|
||||
|
||||
import gi
|
||||
|
||||
|
@ -22,58 +22,83 @@ from gi.repository import GExiv2 as gexiv2
|
|||
_logger = log.module_logger(__name__)
|
||||
|
||||
|
||||
class ExifHandlerGexiv(exif._ExifHandlerBase):
|
||||
"""Main ExifHandler implementation based on gexiv2."""
|
||||
class MetadataGexiv2(metadata.MetadataPlugin):
|
||||
"""Provides metadata support based on gexiv2.
|
||||
|
||||
MESSAGE_SUFFIX = " by gexiv2."
|
||||
Implements `get_metadata`, `get_keys`, `copy_metadata`, and `get_date_time`.
|
||||
"""
|
||||
|
||||
def __init__(self, path: str) -> None:
|
||||
self._path = path
|
||||
|
||||
def __init__(self, filename=""):
|
||||
super().__init__(filename)
|
||||
try:
|
||||
self._metadata = gexiv2.Metadata(filename)
|
||||
self._metadata = gexiv2.Metadata(path)
|
||||
except gi.repository.GLib.GError:
|
||||
_logger.debug("File %s not found", filename)
|
||||
_logger.debug("File %s not found", path)
|
||||
self._metadata = None
|
||||
|
||||
def get_formatted_exif(self, desired_keys: Sequence[str]) -> exif.ExifDictT:
|
||||
exif = {}
|
||||
@staticmethod
|
||||
def name() -> str:
|
||||
"""Get the name of the used backend."""
|
||||
return "gexiv2"
|
||||
|
||||
for base_key in desired_keys:
|
||||
# For backwards compability, assume it has one of the following prefixes
|
||||
for prefix in ["", "Exif.Image.", "Exif.Photo."]:
|
||||
key = f"{prefix}{base_key}"
|
||||
try:
|
||||
exif[key] = (
|
||||
self._metadata.try_get_tag_label(key),
|
||||
self._metadata.try_get_tag_interpreted_string(key),
|
||||
)
|
||||
break
|
||||
@staticmethod
|
||||
def version() -> str:
|
||||
"""Get the version of the used backend."""
|
||||
return "0.10"
|
||||
|
||||
except gi.repository.GLib.GError:
|
||||
_logger.debug("Key %s is invalid for the current image", key)
|
||||
def get_metadata(self, desired_keys: Sequence[str]) -> metadata.MetadataDictT:
|
||||
"""Get value of all desired keys for the current image."""
|
||||
out = {}
|
||||
|
||||
return exif
|
||||
if self._metadata is None:
|
||||
return {}
|
||||
|
||||
for key in desired_keys:
|
||||
try:
|
||||
out[key] = (
|
||||
self._metadata.try_get_tag_label(key),
|
||||
self._metadata.try_get_tag_interpreted_string(key),
|
||||
)
|
||||
except gi.repository.GLib.GError:
|
||||
_logger.debug("Key %s is invalid for the current image", key)
|
||||
|
||||
return out
|
||||
|
||||
def get_keys(self) -> Iterable[str]:
|
||||
"""Get the keys for all metadata values available for the current image."""
|
||||
if self._metadata is None:
|
||||
return iter([])
|
||||
|
||||
return (key for key in self._metadata if not is_hex(key.rpartition(".")[2]))
|
||||
|
||||
def copy_exif(self, dest: str, reset_orientation: bool = True) -> None:
|
||||
def copy_metadata(self, dest: str, reset_orientation: bool = True) -> bool:
|
||||
"""Copy metadata from the current image to dest image."""
|
||||
if self._metadata is None:
|
||||
return False
|
||||
|
||||
if reset_orientation:
|
||||
with contextlib.suppress(KeyError):
|
||||
self._metadata.set_orientation(exif.ExifOrientation.Normal)
|
||||
self._metadata.set_orientation(metadata.ExifOrientation.Normal)
|
||||
|
||||
try:
|
||||
self._metadata.save_file(dest)
|
||||
|
||||
_logger.debug("Successfully wrote exif data for '%s'", dest)
|
||||
return True
|
||||
|
||||
# TODO error handling
|
||||
except gi.repository.GLib.GError as e:
|
||||
_logger.debug("Failed to write exif data for '%s': '%s'", dest, str(e))
|
||||
_logger.debug("Failed to write metadata for '%s': '%s'", dest, str(e))
|
||||
return False
|
||||
|
||||
def get_date_time(self) -> str:
|
||||
"""Get creation date and time of the current image as formatted string."""
|
||||
if self._metadata is None:
|
||||
return ""
|
||||
|
||||
def exif_date_time(self) -> str:
|
||||
with contextlib.suppress(gi.repository.GLib.GError):
|
||||
return self._metadata.get_tag_raw("Exif.Image.DateTime")
|
||||
return ""
|
||||
|
||||
|
||||
def init(*_args: Any, **_kwargs: Any) -> None:
|
||||
exif.set_handler(ExifHandlerGexiv)
|
||||
metadata.register(MetadataGexiv2)
|
||||
|
|
Loading…
Reference in New Issue