1. Alexandre Rossi
  2. lazygal

Commits

Alexandre Rossi  committed 5a3b28b Merge

merge migration to GExiv2

  • Participants
  • Parent commits 251048a, ce72ca6
  • Branches default

Comments (0)

Files changed (9)

File README.md

View file
 
   *   [Python][1] >= 2.6.
   *   [Python imaging library (PIL)][4] >= 1.1.6.
-  *   [pyexiv2][5], a Python binding to [exiv2][6], a library to access image metadata.
+  *   [GExiv2][5] >= 0.5 (to have GObject introspection) which provides Python binding to [exiv2][6], a library to access image metadata.
   *   [Genshi][7] >= 0.5, a *Python toolkit for generation of output for the web*.
   *   [Python GStreamer][23] and associated plugins for video transcoding.
 
   *   `xsltproc` to build manpages from docbook sources. It is included in the [libxslt package][8].
 
  [4]: http://www.pythonware.com/products/pil/
- [5]: http://tilloy.net/dev/pyexiv2/
+ [5]: http://redmine.yorba.org/projects/gexiv2/wiki
  [6]: http://exiv2.org/
  [7]: http://genshi.edgewall.org/
  [23]: http://gstreamer.freedesktop.org/modules/gst-python.html

File devscripts/copy-metadata

View file
 sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
 
 
-from lazygal import pyexiv2api as pyexiv2
+from gi.repository import GExiv2
 
 
 def copy_metadata(src, dst):
-    source_image = pyexiv2.ImageMetadata(src)
-    source_image.read()
-    dest_image = pyexiv2.ImageMetadata(dst)
-    dest_image.read()
+    source_image = GExiv2.Metadata(src)
+    dest_image = GExiv2.Metadata(dst)
 
     # Save dimensions
-    if 'Exif.Photo.PixelXDimension' in dest_image.exif_keys\
-    and 'Exif.Photo.PixelYDimension' in dest_image.exif_keys:
+    if 'Exif.Photo.PixelXDimension' in dest_image \
+    and 'Exif.Photo.PixelYDimension' in dest_image:
         dst_width = dest_image["Exif.Photo.PixelXDimension"]
         dst_height = dest_image["Exif.Photo.PixelYDimension"]
         has_dims = True
     else:
         has_dims = False
 
-    source_image.copy(dest_image)
+    for tag in source_image.get_exif_tags():
+        dest_image[tag] = source_image[tag]
 
     if has_dims:
         # set EXIF image size info to resized size
         dest_image["Exif.Photo.PixelXDimension"] = dst_width
         dest_image["Exif.Photo.PixelYDimension"] = dst_height
 
-    dest_image.comment = source_image.comment
-    dest_image.write()
+    dest_image.save_file()
 
 
 if __name__ == "__main__":

File lazygal-setcomment.py

View file
 
 import sys
 
-from lazygal import pyexiv2api as pyexiv2
+from gi.repository import GExiv2
 
 fn = sys.argv[1]
 comment = sys.argv[2]
 
-im = pyexiv2.ImageMetadata(fn.decode(sys.getfilesystemencoding()))
-im.read()
+im = GExiv2.Metadata(fn.decode(sys.getfilesystemencoding()))
 
 # Assume comment is in utf-8, more encoding processing example using
 # sys.stdin.encoding and example processing in lazygal/metadata.py
 im['Exif.Photo.UserComment'] = comment
-im.write()
+im.save_file()

File lazygal/genmedia.py

View file
 import genfile
 import eyecandy
 import mediautils
-from lazygal import pyexiv2api as pyexiv2
+from gi.repository import GExiv2
 
 
 THUMB_SIZE_NAME = 'thumb'
     )
 
     def copy_metadata(self):
-        imgtags = pyexiv2.ImageMetadata(self.source_media.path)
-        imgtags.read()
-        dest_imgtags = pyexiv2.ImageMetadata(self.path)
-        dest_imgtags.read()
-        imgtags.copy(dest_imgtags)
+        imgtags = GExiv2.Metadata(self.source_media.path)
+        dest_imgtags = GExiv2.Metadata(self.path)
+        for tag in imgtags.get_exif_tags():
+            dest_imgtags[tag] = imgtags[tag]
 
         new_size = self.get_size()
-        dest_imgtags['Exif.Photo.PixelXDimension'] = new_size[0]
-        dest_imgtags['Exif.Photo.PixelYDimension'] = new_size[1]
+        dest_imgtags['Exif.Photo.PixelXDimension'] = str(new_size[0])
+        dest_imgtags['Exif.Photo.PixelYDimension'] = str(new_size[1])
 
         if self.get_rotation() != 0:
             # Smaller image has been rotated in order to be displayed correctly
             # in a web browser. Fix orientation tag accordingly.
-            dest_imgtags['Exif.Image.Orientation'] = 1
+            dest_imgtags['Exif.Image.Orientation'] = '1'
 
         # Those are removed from published pics due to pivacy concerns,
         # unless explicitly told to keep them in. Option to retain GPS
         if not self.webgal.keep_gps:
             for tag in self.PRIVATE_IMAGE_TAGS:
                 try:
-                    del dest_imgtags[tag]
+                    dest_imgtags.clear_tag(tag)
                 except KeyError:
                     pass
         try:
-            dest_imgtags.write()
-        except ValueError, e:
+            dest_imgtags.save_file()
+        except Exception, e:
             logging.error(_("Could not copy metadata in reduced picture: %s") % e)
 
     def save(self, im):

File lazygal/metadata.py

View file
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
+from __future__ import division
+
 import os
 import locale
 import logging
 import codecs
 import datetime
 
-from lazygal import pyexiv2api as pyexiv2
+from gi.repository import GExiv2
+from PIL import Image as PILImage
+
 from lazygal import make
 
+from fractions import Fraction
 
 FILE_METADATA_ENCODING = locale.getpreferredencoding()
 
 FILE_METADATA = ('album-name', 'album-description', 'album-picture', )
 FILE_METADATA_MEDIA_SUFFIX = '.comment'
 
+# As per http://www.exiv2.org/tags.html
+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',
+    )
+
+
+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(' ')
+        csetfield = tokens[0]
+        text = ' '.join(tokens[1:])
+        ignore, cset = csetfield.split('=')
+        cset = cset.strip('"')
+    else:
+        cset = None
+        text = raw
+
+    if cset == 'Unicode':
+        encoding = None
+        try:
+            text.decode('utf-8')
+        except UnicodeDecodeError:
+            im = PILImage.open(imgpath)
+            endianess = im.app['APP1'][6:8]
+            if endianess == 'MM':
+                encoding = 'utf-16be'
+            elif endianess == 'II':
+                encoding = 'utf-16le'
+            else:
+                raise ValueError
+        else:
+            encoding = 'utf-8'
+    elif cset == 'Ascii':
+        encoding = 'ascii'
+    elif cset == 'Jis':
+        encoding = 'shift_jis'
+    else:
+        # Fallback to utf-8 as this is mostly the default for Linux
+        # distributions.
+        encoding = 'utf-8'
+
+    # Return the decoded string according to the found encoding.
+    try:
+        return text.decode(encoding)
+    except UnicodeDecodeError:
+        return text.decode(encoding, 'replace')
+
 
 class FileMetadata(object):
 
 
     def __init__(self, image_path):
         self.image_path = image_path
-        self._metadata = pyexiv2.ImageMetadata(self.image_path)
-        self._metadata.read()
-
-    def get_tag_value(self, name):
-        if name.startswith('Iptc.'):
-            # Iptc tags are always lists, so, for now, return the first
-            # element.
-            return self._metadata[name].values[0]
-        else:
-            return self._metadata[name].value
+        self._metadata = GExiv2.Metadata(self.image_path)
 
     def get_date(self):
         """
         as those were filled by camera, Image DateTime can be update by
         software when editing photos later.
         """
-        for date_tag in ('Exif.Photo.DateTimeDigitized',
-                         'Exif.Photo.DateTimeOriginal',
-                         'Exif.Image.DateTime',
-                         ):
-            try:
-                date = self.get_tag_value(date_tag)
-                if type(date) is not datetime.datetime:
-                    # Sometimes, pyexiv2 sends a string. It seems to happen on
-                    # malformed tags.
-                    raise ValueError
-            except (IndexError, ValueError, KeyError):
-                pass
-            else:
-                return date
-
-        # No date could be found in the picture metadata
-        return None
+        return self._metadata.get_date_time()
 
     def get_required_rotation(self):
         try:
-            orientation_code = self.get_tag_value('Exif.Image.Orientation')
+            orientation_code = int(self._metadata['Exif.Image.Orientation'])
             if orientation_code == 8:
                 return 90
             elif orientation_code == 3:
         vendors put different information to both tags.
         """
         try:
-            model = self.get_tag_value('Exif.Image.Model').strip()
+            model = self._metadata['Exif.Image.Model'].strip()
             # Terminate string at \x00
             pos = model.find('\x00')
             if pos != -1:
                 model = model[:14]
             try:
-                vendor = self.get_tag_value('Exif.Image.Make').strip()
+                vendor = self._metadata['Exif.Image.Make'].strip()
                 vendor_l = vendor.lower()
                 model_l = model.lower()
                 # Split vendor to words and check whether they are
                 for word in vendor_l.split(' '):
                     if model_l.find(word) != -1:
                         return model
-                return '%s %s' % (vendor, model)
+                return ' '.join([vendor, model])
             except KeyError:
                 return model
         except KeyError:
     def get_lens_name(self):
         """
         Return name of used lenses. This usually makes sense only for
-        SLR cameras and uses various maker notes. Currently supported
-        for Pentax, Nikon and Minolta (as soon as Exiv2 supports others,
-        support can be added here.
+        SLR cameras and uses various maker notes.
         """
-
-        try:
-            return self._metadata['Exif.Pentax.LensType'].human_value.strip()
-        except (IndexError, ValueError, KeyError):
-            try:
-                ret = self._metadata['Exif.Nikon3.Lens'].human_value.strip()
-                try:
-                    ret2 = self._metadata['Exif.Nikon3.LensType'].human_value.strip()
-                except (IndexError, ValueError, KeyError):
-                    return ret
-                else:
-                    return '%s %s' % (ret, ret2)
-            except (IndexError, ValueError, KeyError):
-                try:
-                    return self._metadata['Exif.Minolta.LensID'].human_value.strip()
-                except (IndexError, ValueError, KeyError):
-                    return ''
+        interpret = self._metadata.get_tag_interpreted_string
+        vendor_values = [interpret(v) for v in VENDOR_EXIF_CODES]
+        return ' '.join([s.strip() for s in vendor_values if s])
 
     def get_exif_string(self, name):
         """
         Reads string from EXIF information.
         """
-        return str(self.get_tag_value(name)).strip(' ')
+        return self._metadata[name].strip(' ')
 
     def get_exif_float(self, name):
         """
         Reads float number from EXIF information (where it is stored as
         fraction or int).
         """
-        val = self.get_tag_value(name)
-        if type(val) == int:
-            return float(val)
-        elif type(val) == tuple:
-            return float(val[0]) / float(val[1])
-        else:
-            return float(val.numerator) / float(val.denominator)
+        val = self._metadata.get_exif_tag_rational(name)
+        return val.numerator / val.denominator
 
     def _fallback_to_encoding(self, encoded_string, encoding='utf-8'):
+        if encoded_string is None: raise ValueError
         if type(encoded_string) is unicode: return encoded_string
         try:
             return encoded_string.decode(encoding)
             return encoded_string.decode(encoding, 'replace')
 
     def get_exif_usercomment(self):
-        ret = self.get_tag_value('Exif.Photo.UserComment').strip(' \0\x00')
+        ret = self._metadata['Exif.Photo.UserComment'].strip(' \0\x00')
+        ret = decode_exif_user_comment(ret, self.image_path)
         if ret == 'User comments':
             return ''
         return ret
             ret = self.get_file_comment()
             if ret is None:
                 ret = self.get_exif_usercomment()
-                ret = self._fallback_to_encoding(ret)
                 if ret == '':
                     raise ValueError
         except (ValueError, KeyError):
             try:
-                ret = self.get_exif_string('Exif.Image.ImageDescription')
+                ret = self._metadata['Exif.Image.ImageDescription']
                 ret = self._fallback_to_encoding(ret)
             except (ValueError, KeyError):
                 try:
-                    ret = self.get_exif_string('Iptc.Application2.ObjectName')
+                    ret = self._metadata['Iptc.Application2.ObjectName']
                     ret = self._fallback_to_encoding(ret)
                 except (ValueError, KeyError):
                     ret = self.get_jpeg_comment()
 
     def get_flash(self):
         try:
-            flash_info = self._metadata['Exif.Photo.Flash'].human_value
+            flash_info = self._metadata.get_tag_interpreted_string('Exif.Photo.Flash')
             return self._fallback_to_encoding(flash_info)
-        except KeyError:
+        except (ValueError, KeyError):
             return ''
 
     def get_exposure(self):
         try:
-            exposure = self.get_tag_value('Exif.Photo.ExposureTime')
-            if type(exposure) == tuple:
-                if exposure[1] == 1:
-                    return "%d s" % exposure[0]
-                else:
-                    return "%d/%d s" % (exposure[0], exposure[1])
-            else:
-                if exposure.denominator == 1:
-                    return "%d s" % exposure.numerator
-                else:
-                    return "%d/%d s" % (exposure.numerator, exposure.denominator)
+            return str(
+                self._metadata.get_exif_tag_rational('Exif.Photo.ExposureTime'))
         except (ValueError, KeyError):
             return ''
 
     def get_iso(self):
         try:
-            return self.get_exif_string('Exif.Photo.ISOSpeedRatings')
+            return self._metadata['Exif.Photo.ISOSpeedRatings']
         except KeyError:
             return ''
 
     def get_fnumber(self):
         try:
-            val = self.get_exif_float('Exif.Photo.FNumber')
-        except KeyError:
+            val = float(self._metadata.get_exif_tag_rational('Exif.Photo.FNumber'))
+        except (KeyError, TypeError):
             return ''
         else:
-            return 'f/%s' % val
+            return 'f/{}'.format(val)
 
     def get_focal_length(self):
         try:
-            flen = self.get_exif_float('Exif.Photo.FocalLength')
+            flen = self._metadata.get_exif_tag_rational('Exif.Photo.FocalLength')
         except KeyError:
             return ''
         else:
             flen = '%s mm' % flen
 
         try:
-            flen35 = self.get_exif_float('Exif.Photo.FocalLengthIn35mmFilm')
+            flen35 = self._metadata.get_exif_tag_rational('Exif.Photo.FocalLengthIn35mmFilm')
         except KeyError:
             pass
         else:
             except (IndexError, KeyError):
                 iwidth = self.get_exif_float_value('Exif.Photo.PixelXDimension')
 
-            fresunit = str(self._metadata['Exif.Photo.FocalPlaneResolutionUnit'].value)
+            fresunit = self._metadata['Exif.Photo.FocalPlaneResolutionUnit']
             factors = {'1': 25.4, '2': 25.4, '3': 10, '4': 1, '5': 0.001}
             try:
                 fresfactor = factors[fresunit]
 
     def get_jpeg_comment(self):
         try:
-            comment = self._metadata.comment.strip(' ')
+            comment = self._metadata.get_comment().strip(' ')
             if '\x00' in comment:
                 raise ValueError  # ignore broken JPEG comments
             return self._fallback_to_encoding(comment)
 
     def get_authorship(self):
         try:
-            author = self.get_exif_string('Exif.Image.Artist')
+            author = self._metadata['Exif.Image.Artist']
             return self._fallback_to_encoding(author)
         except KeyError:
             return ''

File lazygal/pyexiv2api.py

-# Lazygal, a lazy static web gallery generator.
-# Copyright (C) 2011-2012 Alexandre Rossi <alexandre.rossi@gmail.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-"""
-This module provides a simple wrapper to the pyexiv2 API which changed between
-version 0.1 and 0.2. The goal is to provide a wrapper compatible with the
-latest API.
-
-Sample usage :
-
->>> import pyexiv2api as pyexiv2
-
-Now, simply use the latest API. The module has figured out whether to directly
-use the pyexiv2 module if pyexiv2 >= 0.2 is available, or to mimic the new API
-in case you are running with an older version.
-
-"""
-
-
-import sys
-import datetime
-
-import pyexiv2
-from PIL import Image as PILImage
-
-
-def decode_exif_user_comment(raw, imgpath):
-    """
-    Before pyexiv2 0.3, the EXIF user comment was not decoded to a unicode
-    string. This function does exactly that and is used for earlier versions
-    of pyexiv2.
-    """
-    # This field can contain charset information
-    if raw.startswith('charset='):
-        tokens = raw.split(' ')
-        csetfield = tokens[0]
-        text = ' '.join(tokens[1:])
-        ignore, cset = csetfield.split('=')
-        cset = cset.strip('"')
-    else:
-        cset = None
-        text = raw
-
-    if cset == 'Unicode':
-        encoding = None
-        # Starting from 0.20, exiv2 converts unicode comments to UTF-8
-        try:
-            text.decode('utf-8')
-        except UnicodeDecodeError:
-            # Decoding failed, maybe we can assume we are with exiv2 << 0.20
-            im = PILImage.open(imgpath)
-            endianess = im.app['APP1'][6:8]
-            if endianess == 'MM':
-                encoding = 'utf-16be'
-            elif endianess == 'II':
-                encoding = 'utf-16le'
-            else:
-                raise ValueError
-        else:
-            encoding = 'utf-8'
-    elif cset == 'Ascii':
-        encoding = 'ascii'
-    elif cset == 'Jis':
-        encoding = 'shift_jis'
-    else:
-        # Fallback to utf-8 as this is mostly the default for Linux
-        # distributions.
-        encoding = 'utf-8'
-
-    # Return the decoded string according to the found encoding.
-    try:
-        return text.decode(encoding)
-    except UnicodeDecodeError:
-        return text.decode(encoding, 'replace')
-
-
-# This is required at import time for inheritances below.
-if 'ImageMetadata' in dir(pyexiv2):
-    Pyexiv2ImageMetadata = pyexiv2.ImageMetadata
-else:
-    # This is for the interpreter to be happy, but if pyexiv2.ImageMetadata
-    # does not exist, we are with pyexiv2 << 0.2, and the old API, so we won't
-    # be using classes that inherit from Pyexiv2ImageMetadata.
-    Pyexiv2ImageMetadata = object
-
-
-class _ImageMetadata_0_2_2(Pyexiv2ImageMetadata):
-
-    def __init__(self, imgpath):
-        super(_ImageMetadata_0_2_2, self).__init__(imgpath)
-        self.imgpath = imgpath
-
-    def __getitem__(self, key):
-        tag = super(_ImageMetadata_0_2_2, self).__getitem__(key)
-        if key == 'Exif.Photo.UserComment':
-            tag.value = decode_exif_user_comment(tag.value, self.imgpath)
-        return tag
-
-
-class _ImageMetadata_0_2(_ImageMetadata_0_2_2):
-
-    def get_jpeg_comment(self):
-        # comment appeared in pyexiv2 0.2.2, so use PIL
-        im = PILImage.open(self.imgpath)
-        try:
-            return im.app['COM'].strip('\x00')
-        except KeyError:
-            return ''
-
-    comment = property(get_jpeg_comment)
-
-
-class _ImageTag_0_1(object):
-
-    def __init__(self, tag, imgpath, md, key):
-        self._tag = tag
-        self._imgpath = imgpath
-        self._metadata = md
-        self._key = key
-
-    def __getattr__(self, name):
-        if name == 'value':
-            return self.get_value()
-        elif name == 'raw_value':
-            return self._tag
-        elif name == 'human_value':
-            return self.get_interpreted_value()
-        else:
-            raise AttributeError
-
-    def __str__(self):
-        return str(self._tag)
-
-    def get_exif_date(self):
-        """
-        Parses date from EXIF information.
-        """
-        exif_date = str(self._metadata[self._key])
-        date, time = exif_date.split(' ')
-        year, month, day = date.split('-')
-        hour, minute, second = time.split(':')
-        return datetime.datetime(int(year), int(month), int(day),
-                                 int(hour), int(minute), int(second))
-
-    def get_int(self):
-        return int(self._tag)
-
-    def get_interpreted_value(self):
-        return self._metadata.interpretedExifValue(self._key)
-
-    def get_decoded_utf8(self):
-        return self.get_interpreted_value().decode('utf-8')
-
-    def get_decoded_exif_user_comment(self):
-        return decode_exif_user_comment(self._tag, self._imgpath)
-
-    TAG_PYTRANSLATORS = {
-        'Exif.Photo.DateTimeDigitized': 'get_exif_date',
-        'Exif.Photo.DateTimeOriginal' : 'get_exif_date',
-        'Exif.Photo.UserComment'      : 'get_decoded_exif_user_comment',
-        'Exif.Image.DateTime'         : 'get_exif_date',
-        'Exif.Image.Orientation'      : 'get_int',
-    }
-
-    def get_value(self):
-        if self._key in _ImageTag_0_1.TAG_PYTRANSLATORS.keys():
-            translator = getattr(self.__class__,
-                                 _ImageTag_0_1.TAG_PYTRANSLATORS[self._key])
-            return translator(self)
-        else:
-            return self._tag
-
-
-class _ImageMetadata_0_1(object):
-
-    def __init__(self, imgpath):
-        self.imgpath = imgpath
-        self._metadata = pyexiv2.Image(self.imgpath.encode(sys.getfilesystemencoding()))
-
-    def __getitem__(self, key):
-        return _ImageTag_0_1(self._metadata[key], self.imgpath,
-                             self._metadata, key)
-
-    def __setitem__(self, key, value):
-        self._metadata[key] = value
-
-    def __delitem__(self, key):
-        del self._metadata[key]
-
-    def read(self):
-        self._metadata.readMetadata()
-
-    def write(self):
-        self._metadata.writeMetadata()
-
-    def __try_copy_tag_to(self, tag_key, dest_imgtags):
-        try:
-            dest_imgtags._metadata[tag_key] = self[tag_key]
-        except (ValueError, TypeError):
-            pass
-
-    def copy(self, dest_imgtags):
-        try:
-            self._metadata.copyMetadataTo(dest_imgtags._metadata)
-        except (ValueError, TypeError):
-            # Sometimes pyexiv2 (<< 0.2) fails during the copy on a badly
-            # formatted tag, so we try a manual copy here for each tag.
-            for tag_key in self.exif_keys:
-                self.__try_copy_tag_to(tag_key, dest_imgtags)
-            for tag_key in self.iptc_keys:
-                self.__try_copy_tag_to(tag_key, dest_imgtags)
-
-    def get_comment(self): return self._metadata.getComment()
-
-    def set_comment(self, value): self._metadata.setComment(value)
-    comment = property(get_comment, set_comment)
-
-    def get_exif_keys(self): return self._metadata.exifKeys()
-    exif_keys = property(get_exif_keys)
-
-    def get_iptc_keys(self): return self._metadata.iptcKeys()
-    iptc_keys = property(get_iptc_keys)
-
-
-if 'ImageMetadata' in dir(pyexiv2):
-    if 'comment' in dir(pyexiv2.ImageMetadata):
-        # pyexiv2 (>= 0.2.2)
-        if pyexiv2.version_info >= (0, 3, 0):
-            ImageMetadata = pyexiv2.ImageMetadata
-        else:
-            ImageMetadata = _ImageMetadata_0_2_2
-    else:
-        # pyexiv2 (>= 0.2, << 0.2.2)
-        ImageMetadata = _ImageMetadata_0_2
-elif 'Image' in dir(pyexiv2):
-    # pyexiv2 (<< 0.2)
-    ImageMetadata = _ImageMetadata_0_1
-else:
-    raise ImportError('Unrecognized pyexiv2 version.')
-
-
-# vim: ts=4 sw=4 expandtab

File lazygaltest/test_gendeps.py

View file
 from lazygal.generators import WebalbumDir
 from lazygal.sourcetree import Directory
 from lazygal.genpage import WebalbumIndexPage
-from lazygal import pyexiv2api as pyexiv2
 
 
 class TestDeps(LazygalTestGen):

File lazygaltest/test_generators.py

View file
 import lazygal.config
 from lazygal.generators import WebalbumDir
 from lazygal.sourcetree import Directory
-from lazygal import pyexiv2api as pyexiv2
+from gi.repository import GExiv2
 
 
 class TestGenerators(LazygalTestGen):
         img_path = self.add_img(self.source_dir, 'md_filled.jpg')
 
         # Add some metadata
-        gps_data = pyexiv2.ImageMetadata(self.get_sample_path('sample-with-gps.jpg'))
-        gps_data.read()
-        source_image = pyexiv2.ImageMetadata(img_path)
-        source_image.read()
-        gps_data.copy(source_image)
+        gps_data = GExiv2.Metadata(self.get_sample_path('sample-with-gps.jpg'))
+        source_image = GExiv2.Metadata(img_path)
+        for tag in gps_data.get_exif_tags():
+            source_image[tag] = gps_data[tag]
         dummy_comment = 'nice photo'
         source_image['Exif.Photo.UserComment'] = dummy_comment
         dummy_date = datetime.datetime(2011, 2, 3, 12, 51, 43)
-        source_image['Exif.Photo.DateTimeDigitized'] = dummy_date
-        assert 'Exif.GPSInfo.GPSLongitude' in source_image.exif_keys
-        assert 'Exif.GPSInfo.GPSLatitude' in source_image.exif_keys
-        source_image.write()
+        source_image.set_date_time(dummy_date)
+        assert 'Exif.GPSInfo.GPSLongitude' in source_image
+        assert 'Exif.GPSInfo.GPSLatitude' in source_image
+        source_image.save_file()
 
         # Generate album
         dest_dir = self.get_working_path()
         self.album.generate(dest_dir)
 
         dest_img_path = os.path.join(dest_dir, 'md_filled_small.jpg')
-        dest_image = pyexiv2.ImageMetadata(dest_img_path)
-        dest_image.read()
+        dest_image = GExiv2.Metadata(dest_img_path)
 
         # Check that metadata is still here for reduced pictures.
-        self.assertEqual(dest_image['Exif.Photo.UserComment'].value,
-                         dummy_comment)
-        self.assertEqual(dest_image['Exif.Photo.DateTimeDigitized'].value,
-                         dummy_date)
+        self.assertEqual(dest_image['Exif.Photo.UserComment'], dummy_comment)
+        self.assertEqual(dest_image['Exif.Photo.DateTimeDigitized'], dummy_date.strftime('%Y:%m:%d %H:%M:%S'))
 
         # Check that blacklised tags are not present anymore in the reduced
         # picture.
-        def lat(): return dest_image['Exif.GPSInfo.GPSLongitude'].value
+        def lat(): return dest_image['Exif.GPSInfo.GPSLongitude']
         self.assertRaises(KeyError, lat)
 
-        def long(): return dest_image['Exif.GPSInfo.GPSLatitude'].value
+        def long(): return dest_image['Exif.GPSInfo.GPSLatitude']
         self.assertRaises(KeyError, long)
 
     def test_metadata_osize_nopublish(self):
         img_path = self.add_img(self.source_dir, 'md_filled.jpg')
 
         # Add some metadata
-        source_image = pyexiv2.ImageMetadata(img_path)
-        source_image.read()
+        source_image = GExiv2.Metadata(img_path)
         dummy_comment = 'nice photo'
         source_image['Exif.Photo.UserComment'] = dummy_comment
-        source_image.write()
+        source_image.save_file()
 
         # Generate album
         dest_dir = self.get_working_path()
         self.album.generate(dest_dir)
 
         dest_img_path = os.path.join(dest_dir, 'md_filled_small.jpg')
-        dest_image = pyexiv2.ImageMetadata(dest_img_path)
-        dest_image.read()
+        dest_image = GExiv2.Metadata(dest_img_path)
 
         # Check that metadata is not here for reduced pictures.
-        def com(): return dest_image['Exif.Photo.UserComment'].value
+        def com(): return dest_image['Exif.Photo.UserComment']
         self.assertRaises(KeyError, com)
 
     def test_resize_rotate_size(self):
 
         norotate_path = self.add_img(self.source_dir, 'norotate.jpg')
         torotate_path = self.add_img(self.source_dir, 'torotate.jpg')
-        torotate = pyexiv2.ImageMetadata(torotate_path)
-        torotate.read()
-        torotate['Exif.Image.Orientation'] = 8
-        torotate.write()
+        torotate = GExiv2.Metadata(torotate_path)
+        torotate['Exif.Image.Orientation'] = '8'
+        torotate.save_file()
 
         # Generate album
         dest_dir = self.get_working_path()
         for index, pic in enumerate(pics):
 
             img_path = self.add_img(subgal_path, pic)
-            img_exif = pyexiv2.ImageMetadata(img_path)
-            img_exif.read()
+            img_exif = GExiv2.Metadata(img_path)
             for tag in ('Exif.Photo.DateTimeDigitized',
                         'Exif.Photo.DateTimeOriginal',
                         'Exif.Image.DateTime',
                         ):
-                img_exif[tag] = datetime.datetime(2011, months[index], 1)
-            img_exif.write()
+                img_exif[tag] = datetime.datetime(
+                    2011, months[index], 1).strftime('%Y:%m:%d %H:%M:%S')
+            img_exif.save_file()
 
         return subgal_path, pics
 

File lazygaltest/test_metadata.py

View file
 metadata.FILE_METADATA_ENCODING = 'utf-8'  # force for these tests
 from lazygal.generators import Album
 from lazygal.sourcetree import Directory
-from lazygal import pyexiv2api as pyexiv2
+from gi.repository import GExiv2
 
 
 class TestFileMetadata(LazygalTest):
         img_path = self.add_img(self.source_dir, 'captioned_pic.jpg')
 
         # Set dumy comment which should be ignored.
-        im = pyexiv2.ImageMetadata(img_path)
-        im.read()
+        im = GExiv2.Metadata(img_path)
         im['Exif.Photo.UserComment'] = 'comment not to show'
-        im.write()
+        im.save_file()
 
         # Output real comment which should be chosen over the dummy comment.
         image_caption = u'Les élèves forment une ronde dans la <em>cour</em>.'
     def test_focal_length(self):
         sample = 'sample-model-pentax1.jpg'
         im_md = metadata.ImageInfoTags(self.get_sample_path(sample))
-        self.assertEqual(im_md.get_focal_length(), '18.0 mm (35 mm equivalent: 27.0 mm)')
+        self.assertEqual(im_md.get_focal_length(), '18 mm (35 mm equivalent: 27 mm)')
 
     def test_authorship(self):
         sample = 'sample-author-badencoding.jpg'