"""Local EXIF GPS extraction to prefill the map pin (no pixels touched).""" from typing import Optional, Tuple def _to_degrees(tag): try: d, m, s = (float(p.num) / float(p.den) for p in tag.values) return d + m / 60.0 + s / 3600.0 except (AttributeError, TypeError, ValueError, ZeroDivisionError): return None def extract_gps(path) -> Optional[Tuple[float, float]]: try: import exifread except ImportError: return None try: with open(path, "rb") as fh: tags = exifread.process_file(fh, details=False) except Exception: return None lat = _to_degrees(tags.get("GPS GPSLatitude")) lng = _to_degrees(tags.get("GPS GPSLongitude")) if lat is None or lng is None: return None if str(tags.get("GPS GPSLatitudeRef", "N")).strip().upper().startswith("S"): lat = -lat if str(tags.get("GPS GPSLongitudeRef", "E")).strip().upper().startswith("W"): lng = -lng if not (-90 <= lat <= 90 and -180 <= lng <= 180): return None return (lat, lng) def extract_month(path) -> Optional[int]: """Calendar month (1-12) from the EXIF capture date, or None.""" try: import exifread except ImportError: return None try: with open(path, "rb") as fh: tags = exifread.process_file(fh, details=False) except Exception: return None for key in ("EXIF DateTimeOriginal", "EXIF DateTimeDigitized", "Image DateTime"): raw = str(tags.get(key, "")).strip() if not raw: continue date_part = raw.split()[0] # "YYYY:MM:DD" or "YYYY-MM-DD" bits = date_part.replace("-", ":").split(":") if len(bits) >= 2: try: month = int(bits[1]) except ValueError: continue if 1 <= month <= 12: return month return None