Read GPS coordinates from EXIF tags

If GPS information can be found in the EXIF tags, latitude and longitude will be
extracted and added to the `media.exif.gps` variable. Some ideas how to get the
GPS tags from the EXIF tags where borrowed from Eran Sandler's gist (licensed
under MIT license):

    https://gist.github.com/erans/983821
This commit is contained in:
Matthias Vogelgesang
2013-08-01 21:35:02 +02:00
parent 58a9c7d51a
commit 4940bbdc0c
2 changed files with 67 additions and 6 deletions

View File

@@ -234,6 +234,20 @@ templates. If available, you can use:
This will output something like "Monday, 25. June 2013", depending on your
locale.
``media.exif.gps``
If not None, the dict contains two keys ``lat`` and ``lon`` denoting the
GPS coordinates of the location where the image was taken. ``lat`` will
always be referenced to the north pole whereas ``lon`` will be referenced to
east to the prime meridan. To provide a link on an OpenStreetMap you could
write a template like this:
.. code-block:: jinja
{% if media.exif.gps %}
<a href="http://openstreetmap.org/index.html?lat={{
media.exif.gps.lat }}&lon={{ media.exif.long}}">Go to location</a>
{% endif %}
.. _album-information-label:

View File

@@ -20,13 +20,22 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
# Additional copyright notice:
#
# Several lines of code concerning extraction of GPS data from EXIF tags where
# taken from a GitHub Gist by Eran Sandler at
#
# https://gist.github.com/erans/983821
#
# and partially modified. The code in question is licensed under MIT license.
import logging
import pilkit.processors
import sys
from PIL import Image as PILImage
from PIL import ImageDraw, ImageOps
from PIL.ExifTags import TAGS
from PIL.ExifTags import TAGS, GPSTAGS
from pilkit.processors import Transpose, Adjust
from pilkit.utils import save_image
from datetime import datetime
@@ -107,6 +116,29 @@ def add_copyright(img, text):
draw.text((5, img.size[1] - 15), '\xa9 ' + text)
def _get_exif_data(filename):
img = PILImage.open(filename)
exif = img._getexif() or {}
data = dict((TAGS.get(t, t), v) for (t, v) in exif.items())
if 'GPSInfo' in data:
gps_data = {}
for tag in data['GPSInfo']:
gps_data[GPSTAGS.get(tag, tag)] = data['GPSInfo'][tag]
data['GPSInfo'] = gps_data
return data
def _get_degrees(v):
d = float(v[0][0]) / float(v[0][1])
m = float(v[1][0]) / float(v[1][1])
s = float(v[2][0]) / float(v[1][1])
return d + (m / 60.0) + (s / 3600.0)
def get_exif_tags(source):
"""Read EXIF tags from file @source and return a tuple of two dictionaries,
the first one containing the raw EXIF data, the second one a simplified
@@ -117,16 +149,12 @@ def get_exif_tags(source):
if not '.jpg' in source.lower():
return (None, None)
img = PILImage.open(source)
try:
exif = img._getexif()
data = _get_exif_data(source)
except (TypeError, IOError):
exif = None
logger.warning(u'Could not read EXIF data from {0}'.format(source))
return (None, None)
data = dict((TAGS.get(t, t), v) for (t, v) in exif.items()) if exif else {}
simple = {}
# Provide more accessible tags in the 'simple' key
@@ -153,4 +181,23 @@ def get_exif_tags(source):
msg = u'Could not parse DateTimeOriginal of %s: %s' % (source, e)
logger.warning(msg)
if 'GPSInfo' in data:
info = data['GPSInfo']
lat_info = info.get('GPSLatitude')
lon_info = info.get('GPSLongitude')
lat_ref_info = info.get('GPSLatitudeRef')
lon_ref_info = info.get('GPSLongitudeRef')
if lat_info and lon_info and lat_ref_info and lon_ref_info:
lat = _get_degrees(lat_info)
lon = _get_degrees(lon_info)
if lat_ref_info != 'N':
lat = 0 - lat
if lon_ref_info != 'E':
lon = 0 - lon
simple['gps'] = {'lat': lat, 'lon': lon}
return (data, simple)