Change `uploader` to `actor`
[mediagoblin.git] / mediagoblin / tools / exif.py
index ab3f77f0377ce1ffb3745b2b04574e9846aeaefa..fafd987d167680e267b893ab663edd7aa75f23d8 100644 (file)
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-try:
-    from EXIF import process_file, Ratio
-except ImportError:
-    from mediagoblin.tools.extlib.EXIF import process_file, Ratio
+import six
+
+from exifread import process_file
+from exifread.utils import Ratio
 
 from mediagoblin.processing import BadMediaFail
 from mediagoblin.tools.translate import pass_to_ugettext as _
@@ -50,7 +50,10 @@ def exif_fix_image_orientation(im, exif_tags):
     Translate any EXIF orientation to raw orientation
 
     Cons:
-    - REDUCES IMAGE QUALITY by recompressig it
+    - Well, it changes the image, which means we'll recompress
+      it... not a problem if scaling it down already anyway.  We might
+      lose some quality in recompressing if it's at the same-size
+      though
 
     Pros:
     - Prevents neck pain
@@ -62,7 +65,7 @@ def exif_fix_image_orientation(im, exif_tags):
             6: 270,
             8: 90}
         orientation = exif_tags['Image Orientation'].values[0]
-        if orientation in rotation_map.keys():
+        if orientation in rotation_map:
             im = im.rotate(
                 rotation_map[orientation])
 
@@ -73,16 +76,12 @@ def extract_exif(filename):
     """
     Returns EXIF tags found in file at ``filename``
     """
-    exif_tags = {}
-
     try:
-        image = open(filename)
-        exif_tags = process_file(image, details=False)
+        with open(filename, 'rb') as image:
+            return process_file(image, details=False)
     except IOError:
         raise BadMediaFail(_('Could not read the image file.'))
 
-    return exif_tags
-
 
 def clean_exif(exif):
     '''
@@ -96,12 +95,8 @@ def clean_exif(exif):
         'JPEGThumbnail',
         'Thumbnail JPEGInterchangeFormat']
 
-    clean_exif = {}
-
-    for key, value in exif.items():
-        if not key in disabled_tags:
-            clean_exif[key] = _ifd_tag_to_dict(value)
-    return clean_exif
+    return dict((key, _ifd_tag_to_dict(value)) for (key, value)
+            in six.iteritems(exif) if key not in disabled_tags)
 
 
 def _ifd_tag_to_dict(tag):
@@ -117,20 +112,15 @@ def _ifd_tag_to_dict(tag):
         'field_length': tag.field_length,
         'values': None}
 
-    if isinstance(tag.printable, str):
+    if isinstance(tag.printable, six.binary_type):
         # Force it to be decoded as UTF-8 so that it'll fit into the DB
         data['printable'] = tag.printable.decode('utf8', 'replace')
 
     if type(tag.values) == list:
-        data['values'] = []
-        for val in tag.values:
-            if isinstance(val, Ratio):
-                data['values'].append(
-                    _ratio_to_list(val))
-            else:
-                data['values'].append(val)
+        data['values'] = [_ratio_to_list(val) if isinstance(val, Ratio) else val
+                for val in tag.values]
     else:
-        if isinstance(tag.values, str):
+        if isinstance(tag.values, six.binary_type):
             # Force UTF-8, so that it fits into the DB
             data['values'] = tag.values.decode('utf8', 'replace')
         else:
@@ -144,18 +134,19 @@ def _ratio_to_list(ratio):
 
 
 def get_useful(tags):
-    useful = {}
-    for key, tag in tags.items():
-        if key in USEFUL_TAGS:
-            useful[key] = tag
-
-    return useful
+    from collections import OrderedDict
+    return OrderedDict((key, tag) for (key, tag) in six.iteritems(tags))
 
 
 def get_gps_data(tags):
     """
     Processes EXIF data returned by EXIF.py
     """
+    def safe_gps_ratio_divide(ratio):
+        if ratio.den == 0:
+            return 0.0
+        return float(ratio.num) / float(ratio.den)
+
     gps_data = {}
 
     if not 'Image GPSInfo' in tags:
@@ -166,12 +157,12 @@ def get_gps_data(tags):
             'latitude': tags['GPS GPSLatitude'],
             'longitude': tags['GPS GPSLongitude']}
 
-        for key, dat in dms_data.items():
+        for key, dat in six.iteritems(dms_data):
             gps_data[key] = (
                 lambda v:
-                    float(v[0].num) / float(v[0].den) \
-                    + (float(v[1].num) / float(v[1].den) / 60) \
-                    + (float(v[2].num) / float(v[2].den) / (60 * 60))
+                    safe_gps_ratio_divide(v[0]) \
+                    + (safe_gps_ratio_divide(v[1]) / 60) \
+                    + (safe_gps_ratio_divide(v[2]) / (60 * 60))
                 )(dat.values)
 
         if tags['GPS GPSLatitudeRef'].values == 'S':