Create a gist now

Instantly share code, notes, and snippets.

Get Latitude and Longitude from EXIF using PIL
from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS
def get_exif_data(image):
"""Returns a dictionary from the exif data of an PIL Image item. Also converts the GPS Tags"""
exif_data = {}
info = image._getexif()
if info:
for tag, value in info.items():
decoded = TAGS.get(tag, tag)
if decoded == "GPSInfo":
gps_data = {}
for t in value:
sub_decoded = GPSTAGS.get(t, t)
gps_data[sub_decoded] = value[t]
exif_data[decoded] = gps_data
exif_data[decoded] = value
return exif_data
def _get_if_exist(data, key):
if key in data:
return data[key]
return None
def _convert_to_degress(value):
"""Helper function to convert the GPS coordinates stored in the EXIF to degress in float format"""
d0 = value[0][0]
d1 = value[0][1]
d = float(d0) / float(d1)
m0 = value[1][0]
m1 = value[1][1]
m = float(m0) / float(m1)
s0 = value[2][0]
s1 = value[2][1]
s = float(s0) / float(s1)
return d + (m / 60.0) + (s / 3600.0)
def get_lat_lon(exif_data):
"""Returns the latitude and longitude, if available, from the provided exif_data (obtained through get_exif_data above)"""
lat = None
lon = None
if "GPSInfo" in exif_data:
gps_info = exif_data["GPSInfo"]
gps_latitude = _get_if_exist(gps_info, "GPSLatitude")
gps_latitude_ref = _get_if_exist(gps_info, 'GPSLatitudeRef')
gps_longitude = _get_if_exist(gps_info, 'GPSLongitude')
gps_longitude_ref = _get_if_exist(gps_info, 'GPSLongitudeRef')
if gps_latitude and gps_latitude_ref and gps_longitude and gps_longitude_ref:
lat = _convert_to_degress(gps_latitude)
if gps_latitude_ref != "N":
lat = 0 - lat
lon = _convert_to_degress(gps_longitude)
if gps_longitude_ref != "E":
lon = 0 - lon
return lat, lon
# Example ######
if __name__ == "__main__":
image = ... # load an image through PIL's Image object
exif_data = get_exif_data(image)
print get_lat_lon(exif_data)

Lines 17-19 need to be right indented one level right.

erans commented Oct 15, 2011

The _getexif attribute may not exist if you've opened a PNG or GIF file. The following might be a better alternative to line 7:

info = getattr(image, '_getexif', lambda: None)()
oherych commented Mar 21, 2013

lines 23-27:
you can replace by:

return data.get(key, None)

@DieselDraft: Or just data.get(key)

I forked this (and made some minor changes):

matze commented Aug 1, 2013

@erans: What is the licensing status of this piece of code? I am currently adding EXIF support to a static photo gallery generator and one of the requested features is of course support for geotagged photos. Now, that you (and the others) have done everything that's necessary for that, I would like to integrate that. But without any written permission it's just not possible.

erans commented Aug 8, 2013

@matze I will add licensing later today but it's basically MIT do whatever you want just add attribution :-)

matze commented Aug 14, 2013

Thanks for the clarification. You will be of course properly attributed and credited!


Thanks. This helped me a lot even though I'm using exifread. If someone is curious, here is version of _convert_to_degress when using exifread:

def _convert_to_degress(value):
    deg = value[0]
    deg = float(deg.num) / float(deg.den)

    minute = value[1]
    minute = float(minute.num) / float(minute.den)

    sec = value[2]
    sec = float(sec.num) / float(sec.den)

    return deg + (minute / 60.0) + (sec / 3600.0)
valgur commented Nov 27, 2015

Pillow currently has a bug with GPS EXIF information (as of version 3.0.0): python-pillow/Pillow#1477.
Downgraded to 2.9.0 can be used as a temporary workaround.

valgur commented Nov 27, 2015

I created a fork that accepts a list of images as input and prints the GPS lat, lon, altitude, heading, speed and timestamp values in a TSV fromat:


how can i use it to process the images on my django server


you can do much shorter and clearer, see my gist in 25 lines of code :


This was super useful, thank you.

TheChapu commented Mar 2, 2017

line 74
image ="image.jpg")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment