exif_util.dart 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import 'dart:io' as io;
  2. import 'package:exif/exif.dart';
  3. import 'package:intl/intl.dart';
  4. import 'package:logging/logging.dart';
  5. import 'package:photos/models/file.dart';
  6. import "package:photos/models/location/location.dart";
  7. import "package:photos/services/location_service.dart";
  8. import 'package:photos/utils/file_util.dart';
  9. const kDateTimeOriginal = "EXIF DateTimeOriginal";
  10. const kImageDateTime = "Image DateTime";
  11. const kExifDateTimePattern = "yyyy:MM:dd HH:mm:ss";
  12. const kEmptyExifDateTime = "0000:00:00 00:00:00";
  13. final _logger = Logger("ExifUtil");
  14. Future<Map<String, IfdTag>> getExif(File file) async {
  15. try {
  16. final originFile = await getFile(file, isOrigin: true);
  17. if (originFile == null) {
  18. throw Exception("Failed to fetch origin file");
  19. }
  20. final exif = await readExifFromFile(originFile);
  21. if (!file.isRemoteFile && io.Platform.isIOS) {
  22. await originFile.delete();
  23. }
  24. return exif;
  25. } catch (e) {
  26. _logger.severe("failed to getExif", e);
  27. rethrow;
  28. }
  29. }
  30. Future<Map<String, IfdTag>?> getExifFromSourceFile(io.File originFile) async {
  31. try {
  32. final exif = await readExifFromFile(originFile);
  33. return exif;
  34. } catch (e, s) {
  35. _logger.severe("failed to get exif from origin file", e, s);
  36. return null;
  37. }
  38. }
  39. Future<DateTime?> getCreationTimeFromEXIF(
  40. io.File? file,
  41. Map<String, IfdTag>? exifData,
  42. ) async {
  43. try {
  44. assert(file != null || exifData != null);
  45. final exif = exifData ?? await readExifFromFile(file!);
  46. final exifTime = exif.containsKey(kDateTimeOriginal)
  47. ? exif[kDateTimeOriginal]!.printable
  48. : exif.containsKey(kImageDateTime)
  49. ? exif[kImageDateTime]!.printable
  50. : null;
  51. if (exifTime != null && exifTime != kEmptyExifDateTime) {
  52. return DateFormat(kExifDateTimePattern).parse(exifTime);
  53. }
  54. } catch (e) {
  55. _logger.severe("failed to getCreationTimeFromEXIF", e);
  56. }
  57. return null;
  58. }
  59. Location? locationFromExif(Map<String, IfdTag> exif) {
  60. try {
  61. return _gpsDataFromExif(exif).toLocationObj();
  62. } catch (e, s) {
  63. _logger.severe("failed to get location from exif", e, s);
  64. return null;
  65. }
  66. }
  67. Future<Location?> tryLocationFromExif(File file) async {
  68. try {
  69. final exif = await getExif(file);
  70. return locationFromExif(exif);
  71. } catch (e) {
  72. _logger.severe("failed to get location from exif", e);
  73. return null;
  74. }
  75. }
  76. GPSData _gpsDataFromExif(Map<String, IfdTag> exif) {
  77. final Map<String, dynamic> exifLocationData = {
  78. "lat": null,
  79. "long": null,
  80. "latRef": null,
  81. "longRef": null,
  82. };
  83. if (exif["GPS GPSLatitude"] != null) {
  84. exifLocationData["lat"] = exif["GPS GPSLatitude"]!
  85. .values
  86. .toList()
  87. .map((e) => ((e as Ratio).numerator / e.denominator))
  88. .toList();
  89. }
  90. if (exif["GPS GPSLongitude"] != null) {
  91. exifLocationData["long"] = exif["GPS GPSLongitude"]!
  92. .values
  93. .toList()
  94. .map((e) => ((e as Ratio).numerator / e.denominator))
  95. .toList();
  96. }
  97. if (exif["GPS GPSLatitudeRef"] != null) {
  98. exifLocationData["latRef"] = exif["GPS GPSLatitudeRef"].toString();
  99. }
  100. if (exif["GPS GPSLongitudeRef"] != null) {
  101. exifLocationData["longRef"] = exif["GPS GPSLongitudeRef"].toString();
  102. }
  103. return GPSData(
  104. exifLocationData["latRef"],
  105. exifLocationData["lat"],
  106. exifLocationData["longRef"],
  107. exifLocationData["long"],
  108. );
  109. }