January 27, 2012 at 9:21 AM by Dr. Drang
Back in October I wrote a little script that added GPS location information to photos. My idea was to be able to take one photo with my iPhone, which would capture the location in its EXIF metadata, and use the script to transfer that information to all the photos I took with my regular camera at that same location. It works well, and I’ve been using it ever since, but once I had a bunch of photos with location info in them, I needed a tool that would do the converse: show me where they were taken. It turned out to be very easy to write.
The October program is called
coordinate, and I use it like this:
coordinate -g iphone-photo.jpg IMG*
This reads the GPS metadata from the
iphone-photo.jpg file and writes it to all the files that start with
IMG. The new program is called
map, and when I call it,
it reads the GPS info from the image file and opens Google Maps in my browser with a marker at the photo’s location.
Here’s the code for
python: 1: #!/usr/bin/python 2: 3: import pyexiv2 4: import sys 5: import subprocess 6: 7: try: 8: # Open the photo file. 9: photo = sys.argv 10: md = pyexiv2.ImageMetadata(photo) 11: md.read() 12: 13: # Read the GPS info. 14: latref = md['Exif.GPSInfo.GPSLatitudeRef'].value 15: lat = md['Exif.GPSInfo.GPSLatitude'].value 16: lonref = md['Exif.GPSInfo.GPSLongitudeRef'].value 17: lon = md['Exif.GPSInfo.GPSLongitude'].value 18: 19: except: 20: print "No GPS info in file %s" % photo 21: sys.exit() 22: 23: # Convert the latitude and longitude to signed floating point values. 24: latitude = float(lat) + float(lat)/60 + float(lat)/3600 25: longitude = float(lon) + float(lon)/60 + float(lon)/3600 26: if latref == 'S': latitude = -latitude 27: if lonref == 'W': longitude = -longitude 28: 29: # Construct the Google Maps query and open it. 30: query = "http://maps.google.com/maps?q=loc:%.6f,%.6f" % (latitude, longitude) 31: subprocess.call(['open', query])
It uses the standard
subprocess libraries and the distinctly non-standard
pyexiv2 library. Installing
pyexiv2 isn’t the hardest thing in the world, but it takes more than a simple
pip pyexiv2. I have a writeup on how to do it via Homebrew if you’re interested.
The script is easy to read, I think. Lines 9-17 get the name of the file from the command line, open it, and extract the GPS information. If there’s a problem in any of those steps, an exception is raised, and Lines 20-21 print an error message and quit.
Because the latitude and longitude are returned in an odd format (a list of three Fractions, one each for degrees, minutes, and seconds), Lines 24-27 are needed to put them in a format we can use to query Google Maps. The query is then constructed in Line 30, and Line 31 sends it to OS X’s wonderfully useful
open command to be opened in the default browser. The Google Maps API automatically drops a marker at the location and centers the map around the marker.
I could extend the query with more parameters to set the zoom level, force the display to satellite, map, or street view, and so on, but I prefer to stick with the defaults.
There are some obvious improvements I could make:
- Add an option to use Bing instead of Google Maps. With aerial photos, Bing’s oblique bird’s eye view is often more useful than Google’s top view. I haven’t looked yet, but I assume Bing can be queried through the URL just like Google Maps can.
- Rewrite it for a library that’s easier to install than
pyexiv2. This wouldn’t affect me, but would make it easier for others to use.
- Turn it into a Service. This is a trivial change that would produce a big improvement in usability. With a Service, I could just right-click on an image in the Finder and get the location by choosing an item from the popup menu.
If you’re wondering why I don’t just use iPhoto’s built-in mapping tools, it’s because I don’t use iPhoto. I find it very clunky and slow, and its organization system doesn’t work for the photos I take for my job (which is most of my photos). The
map script gives me a quick way to check the location of any photo, regardless of where it’s stored on my computer.