degal/exif.py
author Tero Marttila <terom@fixme.fi>
Sun, 14 Jun 2009 23:57:50 +0300
changeset 121 3bed35e79f41
parent 120 55cb7fc9c8fb
child 122 292aaba6d6ec
permissions -rw-r--r--
fix pyexif2/EXIFpy handlers to try different prefixes
"""
    The various Exif backends that we have
"""

from __future__ import with_statement

import utils

class ExifHandler (object) :
    """
        Our generic interface for Exif data
    """

    def __init__ (self, file) :
        """
            Load Exif data from the given File.
        """

        self.file = file
    
    def image_tag (self, tag, default=None) :
        """
            Load and return the human-readable unicode-safe value for the given main image tag.
        """

        abstract

    def image_tags (self, tags) :
        """
            Load and return the given tags for the main image as a sequence of (tag, value) tuples , following the same
            rules as image_tag, except there should mainly be only one call to this function, encompassing all the
            relevant tags.

            The returned list should omit those values which were not found.
        """
    
        for tag in tags :
            # try and fetch value
            value = self.image_tag(tag)

            # filter out default not-found
            if value is not None :
                yield tag, value

try :
    import pyexiv2

except ImportError :
    PyExiv2_Handler = None

else :
    class PyExiv2_Handler (ExifHandler) :
        NAME = 'pyexiv2'

        def __init__ (self, file) :
            """
                Load as pyexiv2.Image
            """
            
            # create
            self.image = pyexiv2.Image(file.path)

            # load
            self.image.readMetadata()
        
        def image_tag (self, tag, default=None) :
            # try with likely prefixes
            for prefix in ('Exif.Photo', 'Exif.Image') :
                try :
                    return self.image.interpretedExifValue("%s.%s" % (prefix, tag))
                
                except (IndexError, KeyError) :
                    # nope...
                    continue

            else :
                # not ofund
                return default
    
try :
    from lib import EXIF

except ImportError :
    EXIF_Handler = None

else :
    class EXIF_Handler (ExifHandler) :
        NAME = 'EXIFpy'

        def __init__ (self, file) :
            """
                Load using EXIF.process_file
            """
            
            with file.open('rb') as fh :
                self.tags = EXIF.process_file(fh)
        
        def image_tag (self, tag, default=None) :
            # try with likely prefixes
            for prefix in ('Image', 'EXIF') :
                name = prefix + ' ' + tag

                if name in self.tags :
                    return self.tags[name]

            else :
                # not found
                return default

# ExifHandler implementations to use, in preference order
EXIF_HANDLERS = [
    # reasonably fast, but requires the native library and extension module
    PyExiv2_Handler,

    # pure-python, but very, very slow
    EXIF_Handler,
]

# default ExifHandler to use
EXIF_HANDLER = utils.first(EXIF_HANDLERS)

# ExifHandler implementations by name
EXIF_HANDLERS_BY_NAME = dict((h.NAME, h) for h in EXIF_HANDLERS)

def load (config, file) :
    """
        Load Exif data using the configured Exif handler, and return the instance.

        Returns None if there wasn't any Exif handler available for use.
    """

    if config.exif_handler :
        # explicit
        exif_handler = config.exif_handler

    elif config.exif_handler_name :
        # by name
        exif_handler = EXIF_HANDLERS_BY_NAME[config.exif_handler_name]

    else :
        # default
        exif_handler = EXIF_HANDLER
    
    if exif_handler :
        # found one, use it
        return exif_handler(file)

    else :
        # nothing :(
        return None