import os
from mediagoblin import mg_globals as mgg
-
from mediagoblin.processing import BadMediaFail, \
create_pub_filepath, THUMB_SIZE, MEDIUM_SIZE
-
-################################
-# Media processing initial steps
-################################
-
+from mediagoblin.media_types.image.EXIF import process_file
+from mediagoblin.tools.translate import pass_to_ugettext as _
def process_image(entry):
"""
basename = os.path.split(filename_bits[0])[1]
extension = filename_bits[1].lower()
+ # EXIF extraction
+ exif_tags = extract_exif(queued_filename)
+ gps_data = get_gps_data(exif_tags)
+
try:
thumb = Image.open(queued_filename)
except IOError:
raise BadMediaFail()
+ thumb = exif_fix_image_orientation(thumb, exif_tags)
+
thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
# Copy the thumb to the conversion subdir, then remotely.
# file, a `medium.jpg` files is created and later associated with the media
# entry.
medium = Image.open(queued_filename)
- medium_processed = False
+ # Fox orientation
+ medium = exif_fix_image_orientation(medium, exif_tags)
if medium.size[0] > MEDIUM_SIZE[0] or medium.size[1] > MEDIUM_SIZE[1]:
medium.thumbnail(MEDIUM_SIZE, Image.ANTIALIAS)
- medium_filename = 'medium' + extension
- medium_filepath = create_pub_filepath(entry, medium_filename)
- tmp_medium_filename = os.path.join(
- conversions_subdir, medium_filename)
-
- with file(tmp_medium_filename, 'w') as medium_file:
- medium.save(medium_file)
+ medium_filename = 'medium' + extension
+ medium_filepath = create_pub_filepath(entry, medium_filename)
+ tmp_medium_filename = os.path.join(
+ conversions_subdir, medium_filename)
- mgg.public_store.copy_local_to_storage(
- tmp_medium_filename, medium_filepath)
+ with file(tmp_medium_filename, 'w') as medium_file:
+ medium.save(medium_file)
- medium_processed = True
+ mgg.public_store.copy_local_to_storage(
+ tmp_medium_filename, medium_filepath)
# we have to re-read because unlike PIL, not everything reads
# things in string representation :)
as original_file:
original_file.write(queued_file.read())
+ # Remove queued media file from storage and database
mgg.queue_store.delete_file(queued_filepath)
entry.queued_media_file = []
+
+ # Insert media file information into database
media_files_dict = entry.setdefault('media_files', {})
media_files_dict['thumb'] = thumb_filepath
media_files_dict['original'] = original_filepath
- if medium_processed:
- media_files_dict['medium'] = medium_filepath
+ media_files_dict['medium'] = medium_filepath
+
+ # Insert exif data into database
+ media_data = entry.setdefault('media_data', {})
+ media_data['exif'] = clean_exif(exif_tags)
+ 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
+
+ pp = pprint.PrettyPrinter()
+
+ result = extract_exif(sys.argv[1])
+ gps = get_gps_data(result)
+
+ import pdb
+ pdb.set_trace()
+
+ print pp.pprint(
+ result)
{% block title %}{{ media.title }} — {{ super() }}{% endblock %}
{% block mediagoblin_head %}
+ <link rel="stylesheet"
+ href="{{ request.staticdirect('/extlib/leaflet/leaflet.css') }}" />
+<!--[if lte IE 8]><link rel="stylesheet"
+ href="{{ request.staticdirect('/extlib/leaflet/leaflet.ie.css') }}" /><![endif]-->
<script type="text/javascript"
src="{{ request.staticdirect('/js/comment_show.js') }}"></script>
+ <script type="text/javascript"
+ src="{{ request.staticdirect('/extlib/leaflet/leaflet.js') }}"></script>
+ <script type="text/javascript"
+ src="{{ request.staticdirect('/js/geolocation-map.js') }}"></script>
{% endblock mediagoblin_head %}
{% block mediagoblin_content %}
media= media._id) %}
<a class="button_action" href="{{ delete_url }}">{% trans %}Delete{% endtrans %}</a>
{% endif %}
+ {% if media.media_data.exif %}
+ {#-
+ TODO:
+ - Render GPS data in a human-readable format
+
+ <h4>EXIF</h4>
+ <table>
+ {% for tag, value in media.media_data.exif.items() %}
+ <tr>
+ <td>{{ tag }}</td>
+ <td>{{ value }}</td>
+ </tr>
+ {% endfor %}
+ </table>#}
+ {% endif %}
</p>
{% if comments %}
<h3>
{% include "mediagoblin/utils/tags.html" %}
{% endif %}
+ {% if media.media_data.gps %}
+ <h4>Map</h4>
+ <div>
+ {% set gps = media.media_data.gps %}
+ <div id="tile-map" style="width: 100%; height: 196px;">
+ <input type="hidden" id="gps-longitude"
+ value="{{ gps.longitude }}" />
+ <input type="hidden" id="gps-latitude"
+ value="{{ gps.latitude }}" />
+ </div>
+ <p>
+ <small>
+ View on
+ <a href="http://openstreetmap.org/?mlat={{ gps.latitude }}&mlon={{ gps.longitude }}">
+ OpenStreetMap
+ </a>
+ </small>
+ </p>
+ </div>
+ {% endif %}
{% include "mediagoblin/utils/license.html" %}
</div>
{% endblock %}