# HG changeset patch # User Tero Marttila # Date 1245014635 -10800 # Node ID 292aaba6d6ec45e5f07160ae2e9bd8afb33dbc60 # Parent 3bed35e79f41077ad2054c21009feb6f016ced3e auto-orientation, although no mirroring support yet diff -r 3bed35e79f41 -r 292aaba6d6ec degal/exif.py --- a/degal/exif.py Sun Jun 14 23:57:50 2009 +0300 +++ b/degal/exif.py Mon Jun 15 00:23:55 2009 +0300 @@ -6,6 +6,15 @@ import utils +MIRROR_NONE = 0 +MIRROR_HORIZONTAL = 1 +MIRROR_VERTICAL = 2 + +ROTATE_NONE = 0 +ROTATE_90 = 90 +ROTATE_180 = 180 +ROTATE_270 = 270 + class ExifHandler (object) : """ Our generic interface for Exif data @@ -18,12 +27,19 @@ self.file = file + def image_tag_value (self, tag, default=None) : + """ + Load and return the raw binary value for the given main image tag. + """ + + return default + def image_tag (self, tag, default=None) : """ Load and return the human-readable unicode-safe value for the given main image tag. """ - abstract + return default def image_tags (self, tags) : """ @@ -41,6 +57,32 @@ # filter out default not-found if value is not None : yield tag, value + + + def get_orientation (self) : + """ + Get the orientation of the image in terms of mirroring and rotation in integer degrees clockwise. + + Returns a (MIRROR_*, ROTATE_*) tuple, or None if the Orientation tag could not be found. + + Returns None if it could not be found. + """ + + # load value + orientation = self.image_tag_value('Orientation') + + # map to tuple or None + # XXX: these are from EXIFpy, verify + return { + 1: (MIRROR_NONE, ROTATE_NONE ), # Horizontal (normal) + 2: (MIRROR_HORIZONTAL, ROTATE_NONE ), # Mirrored horizontal + 3: (MIRROR_NONE, ROTATE_180 ), # Rotated 180 + 4: (MIRROR_VERTICAL, ROTATE_NONE ), # Mirrored vertical + 5: (MIRROR_HORIZONTAL, ROTATE_270 ), # Mirrored horizontal then rotated 90 CCW + 6: (MIRROR_NONE, ROTATE_90 ), # Rotated 90 CW + 7: (MIRROR_HORIZONTAL, ROTATE_90 ), # Mirrored horizontal then rotated 90 CW + 8: (MIRROR_NONE, ROTATE_270 ), # Rotated 90 CCW + }.get(orientation, None) try : import pyexiv2 @@ -63,6 +105,20 @@ # load self.image.readMetadata() + def image_tag_value (self, tag, default=None) : + # try with likely prefixes + for prefix in ('Exif.Photo', 'Exif.Image') : + try : + return self.image["%s.%s" % (prefix, tag)] + + except (IndexError, KeyError) : + # nope... + continue + + else : + # not ofund + return default + def image_tag (self, tag, default=None) : # try with likely prefixes for prefix in ('Exif.Photo', 'Exif.Image') : diff -r 3bed35e79f41 -r 292aaba6d6ec degal/image.py --- a/degal/image.py Sun Jun 14 23:57:50 2009 +0300 +++ b/degal/image.py Mon Jun 15 00:23:55 2009 +0300 @@ -63,6 +63,20 @@ return exif.load(self.config, self) @lazy_load + def orientation (self) : + """ + Loads the orientation of this image as a (mirroring, rotation) tuple, or None, if the information is not available. + """ + + if self.config.with_exif and self.exif : + # try and find it + return self.exif.get_orientation() + + else : + # no exif data + return None + + @lazy_load def metadata (self) : """ Load and return the metadata for the image as a dictionary diff -r 3bed35e79f41 -r 292aaba6d6ec degal/thumbnail.py --- a/degal/thumbnail.py Sun Jun 14 23:57:50 2009 +0300 +++ b/degal/thumbnail.py Mon Jun 15 00:23:55 2009 +0300 @@ -63,15 +63,49 @@ height = thumb_height return width, height + + def resize (self, img) : + """ + Resize the give image as needed. + """ + + return img.resize(self.size, resample=PIL.Image.ANTIALIAS) + + def auto_orient (self, img, orient_info) : + """ + Automatically orient the image using the given orientation info. + """ + + # unpack + mirroring, rotation = orient_info + + if mirroring : + # XXX + pass + + if rotation : + # since these are in steps of 90 degrees, it should keep the right size + # but gah, PIL wants these as counter-clockwise! + img = img.rotate(360 - rotation) + + # ok + return img def update (self) : """ Render new output thumbnail. """ + # start with origional image + img = self.image.img + # create resized copy of main image, using our size - thumb = self.image.img.resize(self.size, resample=PIL.Image.ANTIALIAS) + img = self.resize(img) + + # got orientation info? + if self.image.orientation : + img = self.auto_orient(img, self.image.orientation) # write it out - thumb.save(self.path) + img.save(self.path)