Skip to content

Instantly share code, notes, and snippets.

@der-pw
Created April 14, 2025 08:39
Show Gist options
  • Select an option

  • Save der-pw/9394d3324934b8000a06634adfde14d3 to your computer and use it in GitHub Desktop.

Select an option

Save der-pw/9394d3324934b8000a06634adfde14d3 to your computer and use it in GitHub Desktop.
This script generates a GPX track from iPhone photos
"""
pics2GPX.py
This script generates a GPX track (output.gpx) from iPhone photos located in the 'pictures' folder.
It extracts GPS coordinates and timestamps from the image metadata (EXIF)
and builds a chronological track in GPX format. This file can be used for mapping,
visualization, or importing into GPS applications.
Requirements:
- Python 3
- Install required packages with:
pip install Pillow gpxpy
Usage:
1. Place your iPhone photos in the “pictures” folder, which is located in the same folder like the script.
2. Run the script. py ./pics2GPX.py
3. The resulting GPX file (output.gpx) will be saved in the current directory.
Created with help from my friend ChatGPT.
"""
import os
from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS
import gpxpy
import gpxpy.gpx
from datetime import datetime
# Converts GPS coordinates from EXIF format to decimal degrees
def convert_to_degrees(value):
def rational_to_float(r):
return float(r[0]) / float(r[1]) if isinstance(r, tuple) else float(r)
d = rational_to_float(value[0])
m = rational_to_float(value[1])
s = rational_to_float(value[2])
return d + (m / 60.0) + (s / 3600.0)
# Extracts GPS metadata from EXIF data
def get_gps_info(exif_data):
gps_info = {}
gps_data = exif_data.get("GPSInfo")
if not gps_data:
return {}
for key in gps_data:
decoded = GPSTAGS.get(key, key)
gps_info[decoded] = gps_data[key]
return gps_info
# Reads EXIF data from an image
def get_exif_data(image):
exif = image._getexif()
if not exif:
return {}
return {
TAGS.get(tag, tag): value
for tag, value in exif.items()
}
# Parses timestamp from EXIF metadata
def parse_exif_datetime(exif):
dt_str = exif.get("DateTimeOriginal") or exif.get("DateTime")
if dt_str:
try:
return datetime.strptime(dt_str, "%Y:%m:%d %H:%M:%S")
except Exception:
pass
return None
# Main function: builds a GPX file from images in a folder
def generate_gpx_from_images(image_folder):
gpx = gpxpy.gpx.GPX()
track = gpxpy.gpx.GPXTrack()
gpx.tracks.append(track)
segment = gpxpy.gpx.GPXTrackSegment()
track.segments.append(segment)
files = sorted(os.listdir(image_folder))
for file in files:
if not file.lower().endswith((".jpg", ".jpeg")):
continue
path = os.path.join(image_folder, file)
print(f"Checking file: {file}")
try:
img = Image.open(path)
exif = get_exif_data(img)
gps = get_gps_info(exif)
if not gps:
print(f"No GPS data in: {file}")
continue
lat = convert_to_degrees(gps["GPSLatitude"])
lon = convert_to_degrees(gps["GPSLongitude"])
if gps.get("GPSLatitudeRef") == "S":
lat *= -1
if gps.get("GPSLongitudeRef") == "W":
lon *= -1
ele = gps.get("GPSAltitude", None)
if isinstance(ele, tuple):
ele = ele[0] / ele[1]
timestamp = parse_exif_datetime(exif)
point = gpxpy.gpx.GPXTrackPoint(
latitude=lat,
longitude=lon,
elevation=ele,
time=timestamp
)
segment.points.append(point)
print(f" -> GPS: {lat:.6f}, {lon:.6f}, Time: {timestamp}")
except Exception as e:
print(f"Error with {file}: {e}")
with open("output.gpx", "w") as f:
f.write(gpx.to_xml())
print(f"\nGPX file created: output.gpx with {len(segment.points)} trackpoints")
# Set the folder containing your images
generate_gpx_from_images("pictures")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment