Comment 3 for bug 382776

Revision history for this message
Stani (stani) wrote :

I've uploaded a fix in the bazaar repository. I've tested this only one image, so a lot of good testing is required now. Droopy, I count on you ;-) I'll upload it to my PPA where it will be available as Phatch-0.2.0.bzr656 or a later version.
https://launchpad.net/~stani/+archive/ppa

$ bzr diff
=== modified file 'phatch/core/api.py'
--- phatch/core/api.py 2009-06-05 00:29:01 +0000
+++ phatch/core/api.py 2009-06-05 17:59:27 +0000
@@ -274,7 +274,7 @@
     result['abort'] = False
     return photo, result

-def flush_log(photo):
+def flush_log(photo, image_file, action=None):
     if photo.log:
         log_error(photo.log,image_file,action,label='Warning')
         photo.log = ''
@@ -285,7 +285,7 @@
         result['skip'] = False
         result['abort'] = False
         #log non fatal errors/warnings
- flush_log(photo)
+ flush_log(photo, image_file, action)
         return photo, result
     except Exception, details:
         folder, image = os.path.split(ensure_unicode(image_file))
@@ -382,7 +382,7 @@
         for action_index, action in enumerate(actions):
             if action.flush_metadata_before:
                 photo.flush_metadata()
- flush_log(photo)
+ flush_log(photo, image_file)
             #update progress
             progress_result = {}
             send.progress_update_index(progress_result,image_index,action_index)
@@ -397,7 +397,7 @@
             elif result['skip']:
                 break
         photo.flush_metadata()
- flush_log(photo)
+ flush_log(photo, image_file, action)
         del photo, progress_result, action_index, action
     send.progress_close()

=== modified file 'phatch/core/lib/formField.py'
--- phatch/core/lib/formField.py 2009-06-05 13:59:16 +0000
+++ phatch/core/lib/formField.py 2009-06-05 17:49:18 +0000
@@ -225,6 +225,7 @@
         BYSIZE+'/'+SUBFOLDER,
         DEFAULT_FOLDER,
         FOLDER_PHATCH,
+ FOLDER+'/'+SUBFOLDER,
         FOLDER,
     ]
     STAMPS = [

=== modified file 'phatch/core/pil.py'
--- phatch/core/pil.py 2009-06-05 13:15:12 +0000
+++ phatch/core/pil.py 2009-06-05 17:54:49 +0000
@@ -39,6 +39,7 @@
     pyexiv2 = None
     exif = False
 WWW_PYEXIV2 = 'http://tilloy.net/dev/pyexiv2/'
+NEEDS_PYEXIV2 = _('pyexiv2 needs to be installed')+' (%s)'%WWW_PYEXIV2

 try:
     from unicoding import ensure_unicode
@@ -82,6 +83,13 @@
         raise Exception('Libtiff tools are needed for "%s" compression'\
             %compression)

+def transpose(image, methods):
+ """Transpose with a sequence of transformations, mainly useful
+ for exif."""
+ for method in methods:
+ image = image.transpose(method)
+ return image
+
 def treshold(a):
     if a <= 128:
         return 255
@@ -144,6 +152,7 @@

 def extract_info_pexif(info,image):
     """pexif = Pil EXIF"""
+ info['Pexif'] = 1
     #check if exif information is available through pil
     if not hasattr(image,'_getexif'):
         return info
@@ -345,6 +354,7 @@
         self._rotate_exif_reverse = None
         self.metadata = {}
         self.init_info(layer,filename,image_index,save_metadata,folder)
+ self.rotate_exif()

     def flush_metadata(self):
         #is there something to be flushed?
@@ -352,8 +362,7 @@
             return
         #throw an error if pyexiv2 is not installed
         if not exif:
- raise ImportError(_('pyexiv2 needs to be installed')\
- +' (%s)'%WWW_PYEXIV2)
+ raise ImportError(NEEDS_PYEXIV2)
         self.log += exif.flush(self.info['path'],self.metadata)
         #as metadata has changed, use new source
         self._exif_source = self.info['path']
@@ -403,7 +412,8 @@
     def save(self,filename,**options):
         """Saves a flattened image"""
         #todo: flatten layers
- image = self.get_layer().image
+ image = transpose(self.get_layer().image,
+ self._rotate_exif_reverse)
         if image.mode == 'CMYK' and filename.lower().endswith('.png'):
             self.log = \
                 _('CMYK has been converted to RGB to save as PNG.')
@@ -467,13 +477,51 @@

     def rotate_exif(self,reverse=False):
         if reverse:
- if not(self._rotate_exif_reverse is None):
- for layer in self.layers.values():
- layer.image = layer.image.transpose(
- self._rotate_exif_reverse)
- self._rotate_exif_reverse = None
+ rotation = self._rotate_exif_reverse
+ self._rotate_exif_reverse = ()
         else:
- pass
+ orientation = self.get_orientation()
+ #see EXIF.py
+ if orientation == 1:
+ rotation = self._rotate_exif_reverse = ()
+ elif orientation == 2:
+ rotation = Image.FLIP_LEFT_RIGHT,
+ self._rotate_exif_reverse = Image.FLIP_LEFT_RIGHT,
+ elif orientation == 3:
+ rotation = Image.ROTATE_180,
+ self._rotate_exif_reverse = Image.ROTATE_180,
+ elif orientation == 4:
+ rotation = Image.FLIP_TOP_BOTTOM,
+ self._rotate_exif_reverse = Image.FLIP_TOP_BOTTOM,
+ elif orientation == 5:
+ rotation = Image.FLIP_LEFT_RIGHT,Image.ROTATE_90
+ self._rotate_exif_reverse = Image.ROTATE_270,Image.FLIP_LEFT_RIGHT
+ elif orientation == 6:
+ self._rotate_exif_reverse = Image.ROTATE_270,
+ rotation = Image.ROTATE_90,
+ elif orientation == 7:
+ rotation = Image.FLIP_LEFT_RIGHT,Image.ROTATE_270
+ self._rotate_exif_reverse = Image.ROTATE_90,Image.FLIP_LEFT_RIGHT
+ elif orientation == 8:
+ rotation = Image.ROTATE_90,
+ self._rotate_exif_reverse = Image.ROTATE_270,
+ else:
+ raise Exception(_('Unknown orientation value (%s)')%orientation)
+ if rotation:
+ for layer in self.layers.values():
+ layer.image = transpose(layer.image,rotation)
+
+ def get_orientation(self):
+ try:
+ return self.info['Pexif.Orientation']
+ except KeyError:
+ if 'Pexif' in self.info:
+ return 1
+ extract_info_pexif(self.info,layers[0])
+ try:
+ orientation = self.info['Pexif.Orientation']
+ except KeyError:
+ return 1

     #---pil
     def apply_pil(self,function,*arg,**keyw):

$ bzr commit -m "take exif orientation in account"
Committing to: /home/stani/sync/python/phatch/trunk/
modified phatch/core/api.py
modified phatch/core/pil.py
modified phatch/core/lib/formField.py
Committed revision 654.