gpx-to-geotags/lib/geotags.py

77 lines
2.3 KiB
Python

import datetime
from fractions import Fraction
from typing import Union
import piexif
"""
Inspiration: https://gist.github.com/c060604/8a51f8999be12fc2be498e9ca56adc72
"""
def to_deg(value, loc):
"""convert decimal coordinates into degrees, munutes and seconds tuple
Keyword arguments: value is float gps-value, loc is direction list ["S", "N"] or ["W", "E"]
return: tuple like (25, 13, 48.343 ,'N')
"""
if value < 0:
loc_value = loc[0]
elif value > 0:
loc_value = loc[1]
else:
loc_value = ""
abs_value = abs(value)
deg = int(abs_value)
t1 = (abs_value - deg) * 60
min = int(t1)
sec = round((t1 - min) * 60, 5)
return deg, min, sec, loc_value
def change_to_rational(number):
"""convert a number to rantional
Keyword arguments: number
return: tuple like (1, 2), (numerator, denominator)
"""
f = Fraction(str(number))
return f.numerator, f.denominator
def generate_geotags(lat: float, lon: float, alt: Union[int, float], timestamp_obj: datetime.datetime, original_exif: dict):
lat_deg = to_deg(lat, ["S", "N"])
lng_deg = to_deg(lon, ["W", "E"])
exiv_lat = (change_to_rational(lat_deg[0]), change_to_rational(lat_deg[1]), change_to_rational(lat_deg[2]))
exiv_lng = (change_to_rational(lng_deg[0]), change_to_rational(lng_deg[1]), change_to_rational(lng_deg[2]))
# Convert date and time to the format required by EXIF
datestamp = timestamp_obj.strftime("%Y:%m:%d")
timestamp = (change_to_rational(timestamp_obj.hour), change_to_rational(timestamp_obj.minute), change_to_rational(timestamp_obj.second))
if alt < 0:
altitude_ref = 1
altitude = abs(alt)
else:
altitude_ref = 0
altitude = alt
gps_ifd = {
piexif.GPSIFD.GPSVersionID: (2, 0, 0, 0),
piexif.GPSIFD.GPSAltitudeRef: altitude_ref,
piexif.GPSIFD.GPSAltitude: change_to_rational(round(altitude)),
piexif.GPSIFD.GPSLatitudeRef: lat_deg[3],
piexif.GPSIFD.GPSLatitude: exiv_lat,
piexif.GPSIFD.GPSLongitudeRef: lng_deg[3],
piexif.GPSIFD.GPSLongitude: exiv_lng,
piexif.GPSIFD.GPSDateStamp: datestamp,
piexif.GPSIFD.GPSTimeStamp: timestamp,
}
gps_exif = {"GPS": gps_ifd}
# Update original exif data to include GPS tag.
original_exif.update(gps_exif)
return original_exif