Skip to content

Instantly share code, notes, and snippets.

@vigevenoj
Created September 9, 2016 14:59
Show Gist options
  • Save vigevenoj/42a1eba4c9c1c3aabc8ca4eb1a71d80f to your computer and use it in GitHub Desktop.
Save vigevenoj/42a1eba4c9c1c3aabc8ca4eb1a71d80f to your computer and use it in GitHub Desktop.
Generate a json file with image location information and then display that on a mapbox map
<!DOCTYPE html>
<html>
<head>
<title>tripmapper</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.css" />
<script src="http://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<style media="screen" type="text/css">
body {
padding: 0;
margin: 0;
}
html, body, #map {
height: 100%;
}
.thumbnail {
maxWidth: 200px; }
.prev {
text-align: left;
width: 45%;
display: inline-block;
vertical-align: top;
/*float: left;*/
}
.next {
text-align: right;
width: 45%;
display: inline-block;
vertical-align: top;
/*float: right;*/
}
</style>
<script>
// set some global state
$photostops = new Object();
// location data is in trip.json
// photo location data is in images.json
// it's an array so for each element in the array:
// latitude & longitude coordinates and a filename
var customOptions = { 'maxWidth': '500', 'maxHeight':'500', 'keepInView': true }
$.getJSON('images.json').done(function( data ) {
$photostops = data
loadMap();
$.each(data, function(i, val) {
// TODO: iterate over the array of photos and add markers to the information stored.
// then use the marker data to generate links to next/previous marker instead of image
if (isNaN(data[i]['latitude'] )|| isNaN(data[i]['longitude']) ) {
console.error(data[i]['latitude'] + ", " + data[i]['longitude'] + " is not valid");
} else {
marker = L.marker([data[i]['latitude'], data[i]['longitude']]).addTo($map);
$photostops[i]['marker'] = marker
var popupContent = '<div class="popup">';
if (!(typeof data[i-1] === 'undefined')) {
popupContent += '<div class="prev"><a href="' + data[i-1]['filename'] + '">Prev</a></div>'
} else {
console.log( data[i-1] );
}
if ( !(typeof data[i+1] === 'undefined')) {
popupContent += '<div class="next"><a href="' + data[i+1]['filename'] + '">Next</a></div>'
} else {
console.log( data[i+1] );
}
popupContent += '<div class="thumbnail">'
+ '<a href="' + data[i]['filename'] + '">' + data[i]['filename']
+ '<img src="' + data[i]['filename'] + '" height="306" width="408"/>'
+ '</a>'
+ '</div>'
+ '</div>';
marker.bindPopup(popupContent, customOptions);
}
});
});
function loadMap() {
defaultLat = $photostops[1]['latitude'];
defaultLong = $photostops[1]['longitude'];
console.log("Starting map at " + defaultLat + ", " + defaultLong);
$map = new L.map('map').setView([defaultLat, defaultLong], 13);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
maxZoom: 18,
id: 'vigevenoj.53e008d2',
accessToken: 'pk.eyJ1IjoidmlnZXZlbm9qIiwiYSI6IjMwYzk0YzZmMjFlNzU2MjFkOGU4OWIxNWU5YzBjZjg5In0.LbhD_uBPGZaDpagI0jNlSA'
}).addTo($map);
}
</script>
</head>
<body>
<div id="map"></div>
<script>
//
</script>
</body>
</html>
"""Script to parse GPS location and time out of photos and return the data as json"""
import argparse
import sys
import os
import exifread
import imghdr
from fractions import Fraction
from collections import defaultdict
import json
def main():
"""Main entry point for script"""
parser = argparse.ArgumentParser(description="Script to parse gps location and time from a directory of photos")
parser.add_argument("source")
args = parser.parse_args()
gps_info_for_files = []
#file_list = get_file_list(args.source)
files = []
if os.path.isdir(args.source):
for(dirpath, dirnames, filenames) in os.walk(args.source):
for filename in filenames:
if os.path.splitext(filename)[1].lower() in ('.jpg', '.jpeg', '.png'):
latitude, longitude = read_gps_data(os.path.join(dirpath,filename))
if latitude and longitude:
this_image = { 'filename': filename, 'latitude': latitude, 'longitude': longitude }
gps_info_for_files.append(this_image)
break
else:
sys.exit(path + " is not a directory")
info = json.dumps(gps_info_for_files)
print info
def read_gps_data(photofile):
"""Read exif gps data from a single image file"""
# Reminder: the values in the exif tags dict are not strings
latitude = None
longitude = None
f = open(photofile, 'rb')
tags = exifread.process_file(f)
for key in tags.keys():
if str(key) == "GPS GPSLongitude":
longitude = _convert_to_degrees(_get_if_exist(tags, key))
if str(key) == "GPS GPSLatitude":
latitude = _convert_to_degrees(_get_if_exist(tags, key))
gps_latitude_ref = str(_get_if_exist(tags, "GPS GPSLatitudeRef"))
gps_longitude_ref = str(_get_if_exist(tags, "GPS GPSLongitudeRef"))
if latitude and gps_latitude_ref and longitude and gps_longitude_ref:
if gps_latitude_ref != "N": # if not north, negative latitude (south of equator)
latitude = 0 - latitude
if gps_longitude_ref != "E": # if not east, negative longitude (west of prime meridian)
longitude = 0 - longitude
return latitude, longitude
def get_timestamp(exif_data):
"""Extract gps timestamp from exif data"""
dt = None
utc = pytz.utc
if "GPSInfo" in exif_data:
gps_time_stamp = exif_data["GPS GPSTimeStamp"]
if 'GPSDateStamp' in exif_data:
gps_date = [int(i) for i in exif_data["GPS GPSTimeStamp"].split(':')]
def _convert_to_degrees(value):
degrees = float(Fraction(str(value.values[0])))
minutes = float(Fraction(str(value.values[1])))
seconds = float(Fraction(str(value.values[2])))
return degrees + (minutes / 60.0) + (seconds / 3600.0)
def _get_if_exist(data, key):
if key in data:
return data[key]
return None
if __name__ == '__main__':
sys.exit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment