terom@120: """ terom@120: The various Exif backends that we have terom@120: """ terom@120: terom@120: from __future__ import with_statement terom@120: terom@120: import utils terom@120: terom@120: class ExifHandler (object) : terom@120: """ terom@120: Our generic interface for Exif data terom@120: """ terom@120: terom@120: def __init__ (self, file) : terom@120: """ terom@120: Load Exif data from the given File. terom@120: """ terom@120: terom@120: self.file = file terom@120: terom@120: def image_tag (self, tag, default=None) : terom@120: """ terom@120: Load and return the human-readable unicode-safe value for the given main image tag. terom@120: """ terom@120: terom@120: abstract terom@120: terom@120: def image_tags (self, tags) : terom@120: """ terom@120: Load and return the given tags for the main image as a sequence of (tag, value) tuples , following the same terom@120: rules as image_tag, except there should mainly be only one call to this function, encompassing all the terom@120: relevant tags. terom@120: terom@120: The returned list should omit those values which were not found. terom@120: """ terom@120: terom@120: for tag in tags : terom@120: # try and fetch value terom@120: value = self.image_tag(tag) terom@120: terom@120: # filter out default not-found terom@120: if value is not None : terom@120: yield tag, value terom@120: terom@120: try : terom@120: import pyexiv2 terom@120: terom@120: except ImportError : terom@120: PyExiv2_Handler = None terom@120: terom@120: else : terom@120: class PyExiv2_Handler (ExifHandler) : terom@120: NAME = 'pyexiv2' terom@120: terom@120: def __init__ (self, file) : terom@120: """ terom@120: Load as pyexiv2.Image terom@120: """ terom@120: terom@120: # create terom@120: self.image = pyexiv2.Image(file.path) terom@120: terom@120: # load terom@120: self.image.readMetadata() terom@120: terom@120: def image_tag (self, tag, default=None) : terom@120: try : terom@120: # XXX: this is wrong terom@120: return self.image.interpretedExifValue("Exif.Photo.%s" % tag) terom@120: terom@120: except (IndexError, KeyError) : terom@120: return default terom@120: terom@120: try : terom@120: from lib import EXIF terom@120: terom@120: except ImportError : terom@120: EXIF_Handler = None terom@120: terom@120: else : terom@120: class EXIF_Handler (ExifHandler) : terom@120: NAME = 'EXIFpy' terom@120: terom@120: def __init__ (self, file) : terom@120: """ terom@120: Load using EXIF.process_file terom@120: """ terom@120: terom@120: with file.open('rb') as fh : terom@120: self.tags = EXIF.process_file(fh) terom@120: terom@120: def image_tag (self, tag, default=None) : terom@120: # XXX: this is wrong terom@120: return self.tags.get('Image %s' % (tag, ), default) terom@120: terom@120: # ExifHandler implementations to use, in preference order terom@120: EXIF_HANDLERS = [ terom@120: # reasonably fast, but requires the native library and extension module terom@120: PyExiv2_Handler, terom@120: terom@120: # pure-python, but very, very slow terom@120: EXIF_Handler, terom@120: ] terom@120: terom@120: # default ExifHandler to use terom@120: EXIF_HANDLER = utils.first(EXIF_HANDLERS) terom@120: terom@120: # ExifHandler implementations by name terom@120: EXIF_HANDLERS_BY_NAME = dict((h.NAME, h) for h in EXIF_HANDLERS) terom@120: terom@120: def load (config, file) : terom@120: """ terom@120: Load Exif data using the configured Exif handler, and return the instance. terom@120: terom@120: Returns None if there wasn't any Exif handler available for use. terom@120: """ terom@120: terom@120: if config.exif_handler : terom@120: # explicit terom@120: exif_handler = config.exif_handler terom@120: terom@120: elif config.exif_handler_name : terom@120: # by name terom@120: exif_handler = EXIF_HANDLERS_BY_NAME[config.exif_handler_name] terom@120: terom@120: else : terom@120: # default terom@120: exif_handler = EXIF_HANDLER terom@120: terom@120: if exif_handler : terom@120: # found one, use it terom@120: return exif_handler(file) terom@120: terom@120: else : terom@120: # nothing :( terom@120: return None terom@120: