diff --git a/lib/date_extractors/exif_extractor.dart b/lib/date_extractors/exif_extractor.dart index c1010f632..565c5ffb0 100644 --- a/lib/date_extractors/exif_extractor.dart +++ b/lib/date_extractors/exif_extractor.dart @@ -27,8 +27,8 @@ Future exifDateTimeExtractor(final File file) async { // 1. If the mimeType is supported by exif_reader, we use the exif_reader library to read exif. If that fails, exiftool is still used as a fallback, cause it's worth a try. // 2. If the mimeType is not supported by exif_reader or null, we try exiftool and don't even attempt exif_reader, because it would be pointless. - //We only read the first 4096 bytes as that's sufficient for MIME type detection - final List headerBytes = await File(file.path).openRead(0, 4096).first; + //We only read the first 128 bytes as that's sufficient for MIME type detection + final List headerBytes = await File(file.path).openRead(0, 128).first; //Getting mimeType. final String? mimeType = lookupMimeType(file.path, headerBytes: headerBytes); diff --git a/lib/exif_writer.dart b/lib/exif_writer.dart index d13531d87..842732989 100644 --- a/lib/exif_writer.dart +++ b/lib/exif_writer.dart @@ -12,16 +12,30 @@ Future writeDateTimeToExif( final DateTime dateTime, final File file, ) async { + final List headerBytes = await File(file.path).openRead(0, 128).first; + final String? mimeTypeFromHeader = lookupMimeType(file.path, headerBytes: headerBytes); + final String? mimeTypeFromExtension = lookupMimeType(file.path); + //Check if the file already has a dateTime in its EXIF data. If function returns a DateTime, there is no need to write it again. Skip. if (await exifDateTimeExtractor(file) != null) { return false; } - //When exiftool is installed + if (exifToolInstalled) { //Even if exifTool is installed, try to use native way for speed first and if it works keep going. If not, use exiftool. - if (_noExifToolDateTimeWriter(file, dateTime)) { + if (mimeTypeFromHeader == 'image/jpeg' && await _noExifToolDateTimeWriter(file, dateTime, mimeTypeFromHeader)) { return true; //If native way was able to write exif data: exit. If not, try exifTool. } + + if (mimeTypeFromExtension != mimeTypeFromHeader) { + log( + "DateWriter - File has a wrong extension indicating '$mimeTypeFromExtension' but actually it is '$mimeTypeFromHeader'. Exiftool would fail, skipping.\n ${file.path}", + level: 'error', + forcePrint: true + ); + return false; + } + final exifFormat = DateFormat('yyyy:MM:dd HH:mm:ss'); final String dt = exifFormat.format(dateTime); final success = await exiftool!.writeExifBatch(file, { @@ -43,7 +57,7 @@ Future writeDateTimeToExif( } } else { //When exiftool is not installed - return _noExifToolDateTimeWriter(file, dateTime); + return _noExifToolDateTimeWriter(file, dateTime, mimeTypeFromHeader); } } @@ -51,12 +65,26 @@ Future writeGpsToExif( final DMSCoordinates coordinates, final File file, ) async { + + final List headerBytes = await File(file.path).openRead(0, 128).first; + final String? mimeTypeFromHeader = lookupMimeType(file.path, headerBytes: headerBytes); + if (exifToolInstalled) { - //When exiftool is installed + final String? mimeTypeFromExtension = lookupMimeType(file.path); //Even if exifTool is installed, try to use native way for speed first and if it works keep going. If not, use exiftool. - if (_noExifGPSWriter(file, coordinates)) { + if (mimeTypeFromHeader == 'image/jpeg' && await _noExifGPSWriter(file, coordinates, mimeTypeFromHeader)) { return true; } + + if (mimeTypeFromExtension != mimeTypeFromHeader) { + log( + "GPSWriter - File has a wrong extension indicating '$mimeTypeFromExtension' but actually it is '$mimeTypeFromHeader'. Exiftool would fail, skipping.\n ${file.path}", + level: 'error', + forcePrint: true + ); + return false; + } + //Check if the file already has EXIF data and if yes, skip. final Map coordinatesMap = await exiftool!.readExifBatch(file, [ 'GPSLatitude', @@ -90,14 +118,22 @@ Future writeGpsToExif( return false; } else { //If exiftool is not installed - return _noExifGPSWriter(file, coordinates); + return _noExifGPSWriter(file, coordinates, mimeTypeFromHeader); } } -bool _noExifToolDateTimeWriter(final File file, final DateTime dateTime) { +Future _noExifToolDateTimeWriter(final File file, final DateTime dateTime, + final String? mimeTypeFromHeader) async { final exifFormat = DateFormat('yyyy:MM:dd HH:mm:ss'); - final String? mimeType = lookupMimeType(file.path); - if (mimeType == 'image/jpeg') { + final String? mimeTypeFromExtension = lookupMimeType(file.path); + if (mimeTypeFromHeader == 'image/jpeg') { + if (mimeTypeFromHeader != mimeTypeFromExtension) { + log( + "DateWriter - File has a wrong extension indicating '$mimeTypeFromExtension'" + " but actually it is '$mimeTypeFromHeader'. Will use native JPEG writer.\n ${file.path}", + level: 'warning' + ); + } //when it's a jpg and the image library can handle it ExifData? exifData; final Uint8List origbytes = file.readAsBytesSync(); @@ -129,7 +165,7 @@ bool _noExifToolDateTimeWriter(final File file, final DateTime dateTime) { } if (!exifToolInstalled) { log( - '[Step 5/8] Found DateTime in json, but missing in EXIF. Writing to $mimeType is not supported without exiftool.', + '[Step 5/8] Found DateTime in json, but missing in EXIF. Writing to $mimeTypeFromHeader is not supported without exiftool.', level: 'warning', forcePrint: true, ); @@ -137,9 +173,16 @@ bool _noExifToolDateTimeWriter(final File file, final DateTime dateTime) { return false; } -bool _noExifGPSWriter(final File file, final DMSCoordinates coordinates) { - final String? mimeType = lookupMimeType(file.path); - if (mimeType == 'image/jpeg') { +Future _noExifGPSWriter(final File file, final DMSCoordinates coordinates, final String? mimeTypeFromHeader) async { + if (mimeTypeFromHeader == 'image/jpeg') { + final String? mimeTypeFromExtension = lookupMimeType(file.path); + if (mimeTypeFromHeader != mimeTypeFromExtension) { + log( + "GPSWriter - File has a wrong extension indicating '$mimeTypeFromExtension'" + " but actually it is '$mimeTypeFromHeader'. Will use native JPEG writer. \n ${file.path}", + level: 'warning' + ); + } //when it's a jpg and the image library can handle it ExifData? exifData; final Uint8List origbytes = file.readAsBytesSync(); @@ -171,12 +214,12 @@ bool _noExifGPSWriter(final File file, final DMSCoordinates coordinates) { if (!exifToolInstalled) { if (isVerbose) { log( - '[Step 5/8] Found Coordinates in json, but missing in EXIF. Writing to $mimeType is not supported without exiftool.', + '[Step 5/8] Found Coordinates in json, but missing in EXIF. Writing to $mimeTypeFromHeader is not supported without exiftool.', level: 'warning', ); } else { print( - '[Step 5/8] [WARNING] Found Coordinates in json, but missing in EXIF. Writing to $mimeType is not supported without exiftool.', + '[Step 5/8] [WARNING] Found Coordinates in json, but missing in EXIF. Writing to $mimeTypeFromHeader is not supported without exiftool.', ); } }