import os import folium from pathlib import Path from PIL import Image, ExifTags from itertools import chain """To do - create gpx file for adding in to existing GPSprune maps - omit all the thumbs - include *.jpeg - can we also do other formats than JPG ? - we want popup that hotlinks to URL of the photo of course """ def get_coordinates(photo_path): """Extracting EXIF data from jpg files requires an external package because the EXIF standard is interpreted differently by the many different implementations of the JPG file format """ try: # Read EXIF data from photo img = Image.open(photo_path) exif_data = img._getexif() # Extract latitude and longitude from EXIF data gps_info = exif_data.get(34853) #'GPSInfo is a dict # This does not mean that all the GPS fields are populated. lat = gps_info.get(2, None) lon = gps_info.get(4, None) isn = gps_info.get(1, None) ise = gps_info.get(3, None) if isn and isn != "N": print(f"{photo_path} WRONG hemisphere N/S {isn}") if ise and ise != "E": print(f"{photo_path} WRONG hemisphere E/W") point = gps_info.get(17, None) # direction the camera is point towards pointref = gps_info.get(16, None) # "M" for magnetic taken = gps_info.get(29, None) # GPS datestamp except: #print(f"{photo_path} - lat/lon exception") # for key, value in gps_info.items(): # print(key, value, value.type()) return None, None # Convert coordinates to decimal format if lat and lon: # lat and lon are tuples e.g. (47.0, 35.0, 5.77) latitude = float(lat[0] + lat[1] / 60 + lat[2] / 3600) longitude = float(lon[0] + lon[1] / 60 + lon[2] / 3600) # Reverse geocode coordinates to get address #address = geolocator.reverse((latitude, longitude)) return latitude, longitude else: # print(f"{photo_path} - lat/lon conversion exception {lat=} {lon=}") # for key, value in gps_info.items(): # print(key, value, type(value)) return None, None # Specify the folder containing the photos #photo_folder = Path("../../expoweb") photo_folder = Path("/mnt/d/EXPO/PHOTOS") #photo_folder = Path("/mnt/d/EXPO/PHOTOS/2019") #photo_folder = Path("/mnt/d/EXPO/PHOTOS/2022/JonoL") # jpeg save_gpx = "photos_jpg.gpx" # these are generators, not lists photosjpg = photo_folder.rglob("*.jpg") photosjpeg = photo_folder.rglob("*.jpeg") photos = chain(photosjpg, photosjpeg) # Initialize a Folium map centered at an initial location map = folium.Map(location=[47.691036, 13.821314], zoom_start=13) photoset = [] # Iterate through photos in the folder for photo_path in photos: if photo_path.stem.startswith("slide_"): #print(f" - abort slide") continue if photo_path.stem.startswith("thumb_"): #print(f" - abort thumb") continue # Extract latitude, longitude, and address from photo latitude, longitude = get_coordinates(photo_path) if latitude and longitude: print(f"{photo_path} {latitude:.6f} {longitude:.6f}") # Create a marker for each photo with its location and address folium.Marker( location=[latitude, longitude], popup=f"{photo_path}", icon=folium.Icon(color="red", icon="camera"), ).add_to(map) photoset.append((photo_path, latitude, longitude)) # Save the folium map as an HTML file map.save("photo_map.html") print(f"Found {len(photoset)} GPS located photos in '{photo_folder}' and subdirectories.") header = """ pmap photo GPS Troggle photos archive """ with open(save_gpx, "w") as f: f.write(header) for p in photoset: photo_path, latitude, longitude = p # add ele= f.write(f' [{photo_path.stem}]photo{str(photo_path).replace(str(photo_folder),"")}\n') f.write(f'\n')