Files
pfm-ocr/lib/core/utils/exif_helper.dart
T
fhanyuh caf8e98378 chore: normalize line endings (CRLF -> LF)
No content changes: git diff --ignore-all-space over these files is empty.
The churn came from editing on Windows against a repo checked out with LF.
2026-08-27 10:40:49 +07:00

86 lines
2.7 KiB
Dart

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<Map<String, double>?> 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;
}
}