import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:exif/exif.dart'; class ExifHelper { /// Extracts GPS coordinates (latitude and longitude) from an image file's EXIF metadata. /// Returns a map with 'latitude' and 'longitude', or null if not found or invalid. static Future?> extractGps(String imagePath) async { try { final file = File(imagePath); if (!await file.exists()) { debugPrint('EXIF extract: File does not exist at $imagePath'); return null; } final bytes = await file.readAsBytes(); final tags = await readExifFromBytes(bytes); if (tags.isEmpty) { debugPrint('EXIF extract: No EXIF tags found in image'); return null; } final latTag = tags['GPS GPSLatitude']; final latRefTag = tags['GPS GPSLatitudeRef']; final lngTag = tags['GPS GPSLongitude']; final lngRefTag = tags['GPS GPSLongitudeRef']; if (latTag == null || latRefTag == null || lngTag == null || lngRefTag == null) { debugPrint('EXIF extract: GPS tags missing in EXIF metadata'); return null; } final double lat = _convertRatioListToDouble(latTag.values.toList()); final double lng = _convertRatioListToDouble(lngTag.values.toList()); final latRef = latRefTag.toString().trim().toUpperCase(); final lngRef = lngRefTag.toString().trim().toUpperCase(); double finalLat = lat; if (latRef == 'S') finalLat = -finalLat; double finalLng = lng; if (lngRef == 'W') finalLng = -finalLng; debugPrint('EXIF extract success: parsed coordinates Lat: $finalLat, Lng: $finalLng'); return { 'latitude': finalLat, 'longitude': finalLng, }; } catch (e) { debugPrint('Error parsing EXIF metadata: $e'); return null; } } static double _convertRatioListToDouble(dynamic values) { if (values == null || values.length < 3) return 0.0; double degrees = _ratioToDouble(values[0]); double minutes = _ratioToDouble(values[1]); double seconds = _ratioToDouble(values[2]); return degrees + (minutes / 60.0) + (seconds / 3600.0); } static double _ratioToDouble(dynamic val) { if (val is Ratio) { return val.numerator / val.denominator; } if (val is num) { return val.toDouble(); } final str = val.toString().trim(); if (str.contains('/')) { final parts = str.split('/'); if (parts.length == 2) { final numVal = double.tryParse(parts[0]) ?? 0.0; final denVal = double.tryParse(parts[1]) ?? 1.0; return numVal / denVal; } } return double.tryParse(str) ?? 0.0; } }