this repo has no description
at main 113 lines 3.3 kB view raw
1import 'dart:io'; 2 3import 'package:exif/exif.dart'; 4 5import '../app_logger.dart'; 6 7const List<String> exifTags = [ 8 'DateTimeOriginal', 9 'ExposureTime', 10 'FNumber', 11 'Flash', 12 'FocalLengthIn35mmFilm', 13 'ISOSpeedRatings', 14 'LensMake', 15 'LensModel', 16 'Make', 17 'Model', 18]; 19 20const int scaleFactor = 1000000; 21 22Future<Map<String, dynamic>?> parseAndNormalizeExif({required File file}) async { 23 try { 24 final Map<String, IfdTag> exifData = await readExifFromBytes(await file.readAsBytes()); 25 appLogger.i('Parsed EXIF data: $exifData'); 26 27 if (exifData.isEmpty) return null; 28 final Map<String, dynamic> normalized = {}; 29 30 for (final entry in exifData.entries) { 31 final fullTag = entry.key; 32 String tag; 33 if (fullTag.contains(' ')) { 34 tag = fullTag.split(' ').last.trim(); 35 } else { 36 tag = fullTag.trim(); 37 } 38 final value = entry.value.printable; 39 final camelKey = tag.isNotEmpty ? tag[0].toLowerCase() + tag.substring(1) : tag; 40 switch (tag) { 41 case 'DateTimeOriginal': 42 normalized[camelKey] = _exifDateToIso(value); 43 break; 44 case 'ExposureTime': 45 normalized[camelKey] = _parseScaledInt(value); 46 break; 47 case 'FNumber': 48 normalized[camelKey] = _parseScaledInt(value); 49 break; 50 case 'Flash': 51 normalized[camelKey] = value; 52 break; 53 case 'FocalLengthIn35mmFilm': 54 normalized[camelKey] = _parseScaledInt(value); 55 break; 56 case 'ISOSpeedRatings': 57 normalized[camelKey] = _parseInt(value); 58 break; 59 case 'LensMake': 60 normalized[camelKey] = value; 61 break; 62 case 'LensModel': 63 normalized[camelKey] = value; 64 break; 65 case 'Make': 66 normalized[camelKey] = value; 67 break; 68 case 'Model': 69 normalized[camelKey] = value; 70 break; 71 } 72 } 73 74 return normalized; 75 } catch (e) { 76 return null; 77 } 78} 79 80int? _parseScaledInt(String? value) { 81 if (value == null) return null; 82 // Handle fraction like "1/40" 83 if (value.contains('/')) { 84 final parts = value.split('/'); 85 if (parts.length == 2) { 86 final numerator = double.tryParse(parts[0].trim()); 87 final denominator = double.tryParse(parts[1].trim()); 88 if (numerator != null && denominator != null && denominator != 0) { 89 return (numerator / denominator * scaleFactor).round(); 90 } 91 } 92 } 93 final numVal = double.tryParse(value.replaceAll(RegExp(r'[^0-9.]'), '')); 94 if (numVal == null) return null; 95 return (numVal * scaleFactor).round(); 96} 97 98int? _parseInt(String? value) { 99 if (value == null) return null; 100 final intVal = int.tryParse(value.replaceAll(RegExp(r'[^0-9]'), '')); 101 if (intVal == null) return null; 102 return intVal * scaleFactor; 103} 104 105String? _exifDateToIso(String? exifDate) { 106 if (exifDate == null) return null; 107 // EXIF format: yyyy:MM:dd HH:mm:ss 108 final match = RegExp(r'^(\d{4}):(\d{2}):(\d{2}) (\d{2}):(\d{2}):(\d{2})$').firstMatch(exifDate); 109 if (match == null) return null; 110 final formatted = 111 '${match.group(1)}-${match.group(2)}-${match.group(3)}T${match.group(4)}:${match.group(5)}:${match.group(6)}'; 112 return formatted; 113}