def initialise(cls, config_store, verbosity): if not GExiv2.initialize(): raise RuntimeError('Failed to initialise GExiv2') GExiv2.log_set_level( max(GExiv2.LogLevel.DEBUG, min(GExiv2.LogLevel.ERROR, 4 - verbosity))) GExiv2.log_use_glib_logging() # Recent versions of Exiv2 have these namespaces defined, but # older versions may not recognise them. The xapGImg URL is # invalid, but Photini doesn't write xapGImg so it doesn't # matter. for prefix, name in (('exifEX', 'http://cipa.jp/exif/1.0/'), ('xapGImg', 'http://ns.adobe.com/xxx/'), ('xmpGImg', 'http://ns.adobe.com/xap/1.0/g/img/'), ('xmpRights', 'http://ns.adobe.com/xap/1.0/rights/')): GExiv2.Metadata.register_xmp_namespace(name, prefix) # Gexiv2 won't register the 'Iptc4xmpExt' namespace as its # abbreviated version 'iptcExt' is already defined. This kludge # registers it by reading some data with the full namespace data = XMP_WRAPPER.format( 'xmlns:Iptc4xmpExt="http://iptc.org/std/Iptc4xmpExt/2008-02-29/"') # open the data to register the namespace GExiv2.Metadata().open_buf(data.encode('utf-8')) # make list of possible character encodings cls.encodings = ['utf-8', 'iso8859-1', 'ascii'] char_set = locale.getdefaultlocale()[1] if char_set: try: name = codecs.lookup(char_set).name if name not in cls.encodings: cls.encodings.append(name) except LookupError: pass
from datetime import datetime from fractions import Fraction import locale import logging import math import os from gi.repository import GObject, GExiv2 import six from .pyqt import QtCore from . import __version__ # pydoc gi.repository.GExiv2.Metadata is useful to see methods available GExiv2.log_set_level(GExiv2.LogLevel.MUTE) class MetadataValue(object): # base for classes that store a metadata value, e.g. a string, int # or latitude & longitude pair def __init__(self, value): assert (value is not None) self.value = value @classmethod def from_exif(cls, value): return cls(value) @classmethod def from_iptc(cls, value):
VENDOR_EXIF_CODES = ( 'Exif.Canon.LensModel', 'Exif.Minolta.LensID', 'Exif.Nikon3.Lens', 'Exif.Nikon3.LensType', 'Exif.OlympusEq.LensModel', 'Exif.OlympusEq.LensType', 'Exif.Panasonic.LensType', 'Exif.Pentax.LensType', 'Exif.Samsung2.LensType', 'Exif.Sigma.LensRange', 'Exif.Sony1.LensID', ) GEXIV2_DATE_FORMAT = '%Y:%m:%d %H:%M:%S' GExiv2.log_set_level(GExiv2.LogLevel.MUTE) # hide exiv2 errors TAGS_OF_INTEREST = ( 'Exif.Photo.DateTimeOriginal', 'Exif.Photo.DateTimeDigitized', 'Exif.Image.DateTime', ) def decode_exif_user_comment(raw, imgpath): """ GExiv2 does not decode EXIF user comment. """ # This field can contain charset information if raw.startswith('charset='): tokens = raw.split(' ')
except ValueError: pass from gi.repository import GObject, GExiv2 import six from photini import __version__ logger = logging.getLogger(__name__) gexiv2_version = '{} {}, GExiv2 {}, GObject {}'.format( ('PyGI', 'pgi')[using_pgi], gi.__version__, GExiv2._version, GObject._version) # pydoc gi.repository.GExiv2.Metadata is useful to see methods available GExiv2.log_set_level(GExiv2.LogLevel.MUTE) def safe_fraction(value): # Avoid ZeroDivisionError when '0/0' used for zero values in Exif if isinstance(value, six.string_types): numerator, sep, denominator = value.partition('/') if denominator and int(denominator) == 0: return Fraction(0.0) return Fraction(value).limit_denominator(1000000) class MetadataValue(object): # base for classes that store a metadata value, e.g. a string, int # or float def __init__(self, value): assert(value is not None)
def debug_metadata(): GExiv2.log_set_level(GExiv2.LogLevel.INFO)