Merge pull request #29 from matze/exif-gps

Read GPS coordinates from EXIF tags
This commit is contained in:
Simon Conseil
2013-08-18 13:39:47 -07:00
6 changed files with 90 additions and 8 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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

View File

@@ -18,7 +18,8 @@ REF = {
'dir1/test1': {
'title': 'An example sub-category',
'thumbnail': '11.jpg',
'medias': ['11.jpg', 'archlinux-kiss-1024x640.png'],
'medias': ['11.jpg', 'archlinux-kiss-1024x640.png',
'flickr_jerquiaga_2394751088_cc-by-nc.jpg'],
},
'dir1/test2': {
'title': 'Test2',

View File

@@ -68,3 +68,22 @@ def test_exif_copy(tmpdir):
raw, simple = get_exif_tags(dst_file)
assert not raw
assert not simple
def test_exif_gps(tmpdir):
"""Test reading out correct geo tags"""
test_image = 'flickr_jerquiaga_2394751088_cc-by-nc.jpg'
src_file = os.path.join(CURRENT_DIR, 'sample', 'pictures', 'dir1', 'test1',
test_image)
dst_file = str(tmpdir.join(test_image))
settings = create_settings(img_size=(400, 300), copy_exif_data=True)
generate_image(src_file, dst_file, settings)
raw, simple = get_exif_tags(dst_file)
assert 'gps' in simple
lat = 35.266666
lon = -117.216666
assert abs(simple['gps']['lat'] - lat) < 0.0001
assert abs(simple['gps']['lon'] - lon) < 0.0001

View File

@@ -31,7 +31,8 @@ def test_zipped_correctly(tmpdir):
assert os.path.basename(zipped1[0]) == 'archive.zip'
zip_file = zipfile.ZipFile(zipped1[0], 'r')
expected = ('11.jpg', 'archlinux-kiss-1024x640.png')
expected = ('11.jpg', 'archlinux-kiss-1024x640.png',
'flickr_jerquiaga_2394751088_cc-by-nc.jpg')
for filename in zip_file.namelist():
assert filename in expected