diff options
author | Joar Wandborg <git@wandborg.com> | 2012-01-16 03:45:58 +0100 |
---|---|---|
committer | Joar Wandborg <git@wandborg.com> | 2012-01-25 23:44:59 +0100 |
commit | a180ca264e937f7f862c09c30ce3fe7f819ff515 (patch) | |
tree | 423dea3858e9c8be51d396287d576f4903a9417c | |
parent | a020391d908ec685d4fc1b14956d1abec6701a77 (diff) | |
download | mediagoblin-a180ca264e937f7f862c09c30ce3fe7f819ff515.tar.lz mediagoblin-a180ca264e937f7f862c09c30ce3fe7f819ff515.tar.xz mediagoblin-a180ca264e937f7f862c09c30ce3fe7f819ff515.zip |
EXIF fixes
- Moved exif functions from mediagoblin.media_types.image.processing
to mediagoblin.tools.exif
- Moved EXIF.py link from mediagoblin.media_types to mediagoblin.tools.extlib
- Refractored and updated EXIF exctraction and presentation
-rw-r--r-- | mediagoblin/media_types/image/processing.py | 113 | ||||
-rw-r--r-- | mediagoblin/templates/mediagoblin/user_pages/media.html | 16 | ||||
-rw-r--r-- | mediagoblin/tools/exif.py | 168 | ||||
l--------- | mediagoblin/tools/extlib/EXIF.py | 1 | ||||
-rw-r--r-- | mediagoblin/tools/extlib/__init__.py | 0 |
5 files changed, 187 insertions, 111 deletions
diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py index 9eb8fa16..f669e1a5 100644 --- a/mediagoblin/media_types/image/processing.py +++ b/mediagoblin/media_types/image/processing.py @@ -20,8 +20,8 @@ import os from mediagoblin import mg_globals as mgg from mediagoblin.processing import BadMediaFail, \ create_pub_filepath, THUMB_SIZE, MEDIUM_SIZE -from mediagoblin.media_types.image.EXIF import process_file -from mediagoblin.tools.translate import pass_to_ugettext as _ +from mediagoblin.tools.exif import exif_fix_image_orientation, \ + extract_exif, clean_exif, get_gps_data, get_useful def process_image(entry): """ @@ -110,112 +110,15 @@ def process_image(entry): # Insert exif data into database media_data = entry.setdefault('media_data', {}) - media_data['exif'] = clean_exif(exif_tags) + media_data['exif'] = { + 'clean': clean_exif(exif_tags)} + media_data['exif']['useful'] = get_useful( + media_data['exif']['clean']) media_data['gps'] = gps_data # clean up workbench workbench.destroy_self() -def exif_fix_image_orientation(im, exif_tags): - """ - Translate any EXIF orientation to raw orientation - - Cons: - - REDUCES IMAGE QUALITY by recompressig it - - Pros: - - Cures my neck pain - """ - # Rotate image - if 'Image Orientation' in exif_tags: - rotation_map = { - 3: 180, - 6: 270, - 8: 90} - orientation = exif_tags['Image Orientation'].values[0] - if orientation in rotation_map.keys(): - im = im.rotate( - rotation_map[orientation]) - - return im - -def extract_exif(filename): - """ - Returns EXIF tags found in file at ``filename`` - """ - exif_tags = {} - - try: - image = open(filename) - exif_tags = process_file(image) - except IOError: - BadMediaFail(_('Could not read the image file.')) - - return exif_tags - -def clean_exif(exif): - # Clean the result from anything the database cannot handle - - # Discard any JPEG thumbnail, for database compatibility - # and that I cannot see a case when we would use it. - # It takes up some space too. - disabled_tags = [ - 'Thumbnail JPEGInterchangeFormatLength', - 'JPEGThumbnail', - 'Thumbnail JPEGInterchangeFormat'] - - clean_exif = {} - - for key, value in exif.items(): - if not key in disabled_tags: - clean_exif[key] = str(value) - - return clean_exif - - -def get_gps_data(exif): - """ - Processes EXIF data returned by EXIF.py - """ - if not 'Image GPSInfo' in exif: - return False - - gps_data = {} - - try: - dms_data = { - 'latitude': exif['GPS GPSLatitude'], - 'longitude': exif['GPS GPSLongitude']} - - for key, dat in dms_data.items(): - 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)) - )(dat.values) - except KeyError: - pass - - try: - gps_data['direction'] = ( - lambda d: - float(d.num) / float(d.den) - )(exif['GPS GPSImgDirection'].values[0]) - except KeyError: - pass - - try: - gps_data['altitude'] = ( - lambda a: - float(a.num) / float(a.den) - )(exif['GPS GPSAltitude'].values[0]) - except KeyError: - pass - - return gps_data - - if __name__ == '__main__': import sys import pprint @@ -224,9 +127,11 @@ if __name__ == '__main__': result = extract_exif(sys.argv[1]) gps = get_gps_data(result) + clean = clean_exif(result) + useful = get_useful(clean) import pdb pdb.set_trace() print pp.pprint( - result) + clean) diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 944d7f6e..60fca710 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -80,20 +80,21 @@ media= media._id) %} <a class="button_action" href="{{ delete_url }}">{% trans %}Delete{% endtrans %}</a> {% endif %} - {% if media.media_data.exif %} + {% if media.media_data.has_key('exif') + and media.media_data.exif.has_key('useful') %} {#- TODO: - Render GPS data in a human-readable format - + #} <h4>EXIF</h4> <table> - {% for tag, value in media.media_data.exif.items() %} + {% for key, tag in media.media_data.exif.useful.items() %} <tr> - <td>{{ tag }}</td> - <td>{{ value }}</td> + <td>{{ key }}</td> + <td>{{ tag.printable }}</td> </tr> {% endfor %} - </table>#} + </table> {% endif %} </p> {% if comments %} @@ -194,7 +195,8 @@ {% include "mediagoblin/utils/tags.html" %} {% endif %} - {% if media.media_data.gps %} + {% if media.media_data.has_key('gps') + and media.media_data.gps %} <h4>Map</h4> <div> {% set gps = media.media_data.gps %} diff --git a/mediagoblin/tools/exif.py b/mediagoblin/tools/exif.py new file mode 100644 index 00000000..445907ba --- /dev/null +++ b/mediagoblin/tools/exif.py @@ -0,0 +1,168 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 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 Affero General Public License for more details. +# +# 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/>. + +from mediagoblin.tools.extlib.EXIF import process_file, Ratio +from mediagoblin.processing import BadMediaFail +from mediagoblin.tools.translate import pass_to_ugettext as _ + +from collections import OrderedDict + +# A list of tags that should be stored for faster access +USEFUL_TAGS = [ + 'Image Make', + 'Image Model', + 'EXIF FNumber', + 'EXIF Flash', + 'EXIF FocalLength', + 'EXIF ExposureTime', + 'EXIF ApertureValue', + 'EXIF ExposureMode', + 'EXIF ISOSpeedRatings', + 'EXIF UserComment', + ] + +def exif_fix_image_orientation(im, exif_tags): + """ + Translate any EXIF orientation to raw orientation + + Cons: + - REDUCES IMAGE QUALITY by recompressig it + + Pros: + - Cures my neck pain + """ + # Rotate image + if 'Image Orientation' in exif_tags: + rotation_map = { + 3: 180, + 6: 270, + 8: 90} + orientation = exif_tags['Image Orientation'].values[0] + if orientation in rotation_map.keys(): + im = im.rotate( + rotation_map[orientation]) + + return im + +def extract_exif(filename): + """ + Returns EXIF tags found in file at ``filename`` + """ + exif_tags = {} + + try: + image = open(filename) + exif_tags = process_file(image) + except IOError: + raise BadMediaFail(_('Could not read the image file.')) + + return exif_tags + +def clean_exif(exif): + ''' + Clean the result from anyt +hing the database cannot handle + ''' + # Discard any JPEG thumbnail, for database compatibility + # and that I cannot see a case when we would use it. + # It takes up some space too. + disabled_tags = [ + 'Thumbnail JPEGInterchangeFormatLength', + '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 + +def _ifd_tag_to_dict(tag): + data = { + 'printable': tag.printable, + 'tag': tag.tag, + 'field_type': tag.field_type, + 'field_offset': tag.field_offset, + 'field_length': tag.field_length, + 'values': None} + 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) + else: + data['values'] = tag.values + + return data + +def _ratio_to_list(ratio): + return [ratio.num, ratio.den] + +def get_useful(tags): + useful = {} + for key, tag in tags.items(): + if key in USEFUL_TAGS: + useful[key] = tag + + return useful + + +def get_gps_data(tags): + """ + Processes EXIF data returned by EXIF.py + """ + if not 'Image GPSInfo' in tags: + return False + + gps_data = {} + + try: + dms_data = { + 'latitude': tags['GPS GPSLatitude'], + 'longitude': tags['GPS GPSLongitude']} + + for key, dat in dms_data.items(): + 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)) + )(dat.values) + except KeyError: + pass + + try: + gps_data['direction'] = ( + lambda d: + float(d.num) / float(d.den) + )(tags['GPS GPSImgDirection'].values[0]) + except KeyError: + pass + + try: + gps_data['altitude'] = ( + lambda a: + float(a.num) / float(a.den) + )(tags['GPS GPSAltitude'].values[0]) + except KeyError: + pass + + return gps_data diff --git a/mediagoblin/tools/extlib/EXIF.py b/mediagoblin/tools/extlib/EXIF.py new file mode 120000 index 00000000..82a2fb30 --- /dev/null +++ b/mediagoblin/tools/extlib/EXIF.py @@ -0,0 +1 @@ +../../../extlib/exif/EXIF.py
\ No newline at end of file diff --git a/mediagoblin/tools/extlib/__init__.py b/mediagoblin/tools/extlib/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/mediagoblin/tools/extlib/__init__.py |