diff --git a/util/import_photos.py b/util/import_photos.py index 32a4065..9fd21a7 100644 --- a/util/import_photos.py +++ b/util/import_photos.py @@ -6,9 +6,50 @@ import filetype from os import path, walk from sys import argv, stderr from shutil import move +from fractions import Fraction import sqlite3 +def decimal_from_rational64u(dms: str, ref): + """Convert coordinates from rational64u EXIF uses to represent + degrees, minutes, and seconds of a point to decimal format + Take into account reference cardinal direction and + turn [S]outh and [W]est coordinates negative + + General formula is + dec_degree = degreesNumerator / degreesDenominator + + minutesNumerator / minutesDenominator / 60 + + secondsNumerator / secondsDenominator / 3600 + + https://en.wikipedia.org/wiki/Geographic_coordinate_conversion + https://gis.stackexchange.com/questions/136925/how-to-parse-exif-gps-information-to-lat-lng-decimal-numbers + + >>> decimal_from_rational64u(dms="42/1, 18/1, 2914/100", "S") + -42.30809 + """ + + # 1 split by comma + # 2 turn each into Fraction + # 3 zip fractions with their respective (degrees, minutes, seconds) denominator + # 4 divide the fraction + # 5 sum up the result + # 6 convert to decimal + # 7 round to 5th decimal point + dec_coordinates = round( + float( + sum( + a / b + for (a, b) in zip((Fraction(f) for f in dms.split(",")), (1, 60, 3600)) + ) + ), + 5, + ) + if ref in ("S", "W"): + dec_coordinates = -dec_coordinates + + return dec_coordinates + + def process_pictures(source: str, dest_shrunk: str, dest_original: str): """Process images from the base directory in the first command line argument. Place the resized copies to dest_shrunk and @@ -53,10 +94,12 @@ def process_pictures(source: str, dest_shrunk: str, dest_original: str): "ResizedImage": path.join(dest_shrunk, filename), "OriginalImage": path.join(dest_original, filename), "DateTimeOriginal": exif["DateTimeOriginal"], # Q: normalize it? - "GPSLatitude": exif["GPSLatitude"], - "GPSLatitudeRef": exif["GPSLatitudeRef"], - "GPSLongitude": exif["GPSLongitude"], - "GPSLongitudeRef": exif["GPSLongitudeRef"], + "GPSLatitude": decimal_from_rational64u( + exif["GPSLatitude"], exif["GPSLatitudeRef"] + ), + "GPSLongitude": decimal_from_rational64u( + exif["GPSLongitude"], exif["GPSLongitudeRef"] + ), } except KeyError as e: print(f"Image '{filename}' has no valid exif") @@ -78,18 +121,14 @@ def update_database(pic_info: dict, db_location: str): """INSERT INTO images(resizedpath, origpath, date, - GPSLatitude, - GPSLatitudeRef, - GPSLongitude, - GPSLongitudeRef) + GPSLatitude, + GPSLongitude) VALUES (:ResizedImage, :OriginalImage, :DateTimeOriginal, :GPSLatitude, - :GPSLatitudeRef, - :GPSLongitude, - :GPSLongitudeRef) + :GPSLongitude) """, pic_info, ) @@ -120,10 +159,8 @@ def check_database(database_path: str): resizedpath TEXT NOT NULL, origpath TEXT NOT NULL, date TEXT, - GPSLatitude TEXT, - GPSLatitudeRef TEXT, - GPSLongitude TEXT, - GPSLongitudeRef TEXT + GPSLatitude REAL, + GPSLongitude REAL )""" ) con.commit()