From 039f7adbc63faae1314ca535d713c5789c816841 Mon Sep 17 00:00:00 2001 From: EtiennePelletier Date: Wed, 4 Nov 2020 20:41:21 -0500 Subject: [PATCH] Modify get_gps_coords util to handle tags in native Python --- exifread/utils.py | 64 +++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/exifread/utils.py b/exifread/utils.py index 2d11ffc..b87944f 100644 --- a/exifread/utils.py +++ b/exifread/utils.py @@ -3,6 +3,7 @@ """ from fractions import Fraction +from typing import Tuple, Union def ord_(dta): @@ -41,32 +42,47 @@ def make_string_uc(seq) -> str: return make_string(seq) -def get_gps_coords(tags: dict) -> tuple: - - lng_ref_tag_name = 'GPS GPSLongitudeRef' - lng_tag_name = 'GPS GPSLongitude' - lat_ref_tag_name = 'GPS GPSLatitudeRef' - lat_tag_name = 'GPS GPSLatitude' - - # Check if these tags are present - gps_tags = [lng_ref_tag_name, lng_tag_name, lat_tag_name, lat_tag_name] - for tag in gps_tags: - if not tag in tags.keys(): - return () - - lng_ref_val = tags[lng_ref_tag_name].values - lng_coord_val = [c.decimal() for c in tags[lng_tag_name].values] - - lat_ref_val = tags[lat_ref_tag_name].values - lat_coord_val = [c.decimal() for c in tags[lat_tag_name].values] - - lng_coord = sum([c/60**i for i, c in enumerate(lng_coord_val)]) - lng_coord *= (-1) ** (lng_ref_val == 'W') +def degrees_to_decimal(degrees: float, minutes: float, seconds: float) -> float: + """ + Converts coordinates from a degrees minutes seconds format to a decimal degrees format. + Reference: https://en.wikipedia.org/wiki/Geographic_coordinate_conversion + """ + return degrees + minutes/60 + seconds/3600 - lat_coord = sum([c/60**i for i, c in enumerate(lat_coord_val)]) - lat_coord *= (-1) ** (lat_ref_val == 'S') - return (lat_coord, lng_coord) +def get_gps_coords(tags: dict) -> Union[Tuple[float, float], None]: + """ + Extract tuple of latitude and longitude values in decimal degrees format from EXIF tags. + Return None if no GPS coordinates are found. + Handles regular and serialized Exif tags. + """ + gps = { + 'lat_coord': 'GPS GPSLatitude', + 'lat_ref': 'GPS GPSLatitudeRef', + 'lng_coord': 'GPS GPSLongitude', + 'lng_ref': 'GPS GPSLongitudeRef' + } + + # Verify if required keys are a subset of provided tags + if not set(gps.values()) <= tags.keys(): + return None + + # If tags have not been converted to native Python types, do it + if not isinstance(tags[gps['lat_coord']], list): + tags[gps['lat_coord']] = [c.decimal() for c in tags[gps['lat_coord']].values] + tags[gps['lng_coord']] = [c.decimal() for c in tags[gps['lng_coord']].values] + tags[gps['lat_ref']] = tags[gps['lat_ref']].values + tags[gps['lng_ref']] = tags[gps['lng_ref']].values + + lat = degrees_to_decimal(*tags[gps['lat_coord']]) + if tags[gps['lat_ref']] == 'S': + lat *= -1 + + lng = degrees_to_decimal(*tags[gps['lng_coord']]) + if tags[gps['lng_ref']] == 'W': + lng *= -1 + + return lat, lng class Ratio(Fraction):