Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/date_extractors/exif_extractor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ Future<DateTime?> 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<int> 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<int> headerBytes = await File(file.path).openRead(0, 128).first;

//Getting mimeType.
final String? mimeType = lookupMimeType(file.path, headerBytes: headerBytes);
Expand Down
73 changes: 58 additions & 15 deletions lib/exif_writer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,30 @@ Future<bool> writeDateTimeToExif(
final DateTime dateTime,
final File file,
) async {
final List<int> 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, {
Expand All @@ -43,20 +57,34 @@ Future<bool> writeDateTimeToExif(
}
} else {
//When exiftool is not installed
return _noExifToolDateTimeWriter(file, dateTime);
return _noExifToolDateTimeWriter(file, dateTime, mimeTypeFromHeader);
}
}

Future<bool> writeGpsToExif(
final DMSCoordinates coordinates,
final File file,
) async {

final List<int> 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',
Expand Down Expand Up @@ -90,14 +118,22 @@ Future<bool> 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<bool> _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();
Expand Down Expand Up @@ -129,17 +165,24 @@ 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,
);
}
return false;
}

bool _noExifGPSWriter(final File file, final DMSCoordinates coordinates) {
final String? mimeType = lookupMimeType(file.path);
if (mimeType == 'image/jpeg') {
Future<bool> _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();
Expand Down Expand Up @@ -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.',
);
}
}
Expand Down