// There is an issue with Reconyx cameras in how it stores the original 'Date / ime' metadata tag's value // To get around this, we first try to get that tag's value using the standard method. If it doesn't work, // we try again using the Reconyx-specific method. public static bool TryReadDateTimeOriginalFromMetadata(string filePath, out DateTime dateTime) { dateTime = DateTime.MinValue; // Use only on images, as video files don't contain the desired metadata. try { IReadOnlyList <MetadataDirectory> metadataDirectories = null; // Performance tweaks. Reading in sequential scan, does this speed up? Under the covers, the MetadataExtractor is using a sequential read, allowing skip forward but not random access. // Exif is small, do we need a big block? using (FileStream fS = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 64, FileOptions.SequentialScan)) { metadataDirectories = ImageMetadataReader.ReadMetadata(fS); } ExifSubIfdDirectory exifSubIfd = metadataDirectories.OfType <ExifSubIfdDirectory>().FirstOrDefault(); if (exifSubIfd == null) { return(false); } if (exifSubIfd.TryGetDateTime(ExifSubIfdDirectory.TagDateTimeOriginal, out dateTime) == false) { // We couldn't read the metadata. In case its a reconyx camera, the fallback is to use the Reconyx-specific metadata using its DateTimeOriginal tag ReconyxHyperFireMakernoteDirectory reconyxMakernote = metadataDirectories.OfType <ReconyxHyperFireMakernoteDirectory>().FirstOrDefault(); if ((reconyxMakernote == null) || (reconyxMakernote.TryGetDateTime(ReconyxHyperFireMakernoteDirectory.TagDateTimeOriginal, out dateTime) == false)) { return(false); } } return(true); } catch { return(false); } }
public DateTimeAdjustmentEnum TryReadDateTimeOriginalFromMetadata(string folderPath, TimeZoneInfo imageSetTimeZone) { // Use only on images, as video files don't contain the desired metadata. try { IReadOnlyList <MetadataDirectory> metadataDirectories = null; // PERFORMANCE // IReadOnlyList<MetadataDirectory> metadataDirectories = ImageMetadataReader.ReadMetadata(this.GetFilePath(folderPath)); // Reading in sequential scan, does this speed up? Under the covers, the MetadataExtractor is using a sequential read, allowing skip forward but not random access. // Exif is small, do we need a big block? using (FileStream fS = new FileStream(this.GetFilePath(folderPath), FileMode.Open, FileAccess.Read, FileShare.Read, 64, FileOptions.SequentialScan)) { metadataDirectories = ImageMetadataReader.ReadMetadata(fS); } ExifSubIfdDirectory exifSubIfd = metadataDirectories.OfType <ExifSubIfdDirectory>().FirstOrDefault(); if (exifSubIfd == null) { return(DateTimeAdjustmentEnum.MetadataNotUsed); } if (exifSubIfd.TryGetDateTime(ExifSubIfdDirectory.TagDateTimeOriginal, out DateTime dateTimeOriginal) == false) { // We couldn't read the metadata. In case its a reconyx camera, the fallback is to use the Reconyx-specific metadata ReconyxHyperFireMakernoteDirectory reconyxMakernote = metadataDirectories.OfType <ReconyxHyperFireMakernoteDirectory>().FirstOrDefault(); if ((reconyxMakernote == null) || (reconyxMakernote.TryGetDateTime(ReconyxHyperFireMakernoteDirectory.TagDateTimeOriginal, out dateTimeOriginal) == false)) { return(DateTimeAdjustmentEnum.MetadataNotUsed); } } DateTimeOffset exifDateTime = DateTimeHandler.CreateDateTimeOffset(dateTimeOriginal, imageSetTimeZone); // get the current date time DateTimeOffset currentDateTime = this.DateTimeIncorporatingOffset; // measure the extent to which the file time and 'image taken' metadata are consistent bool dateAdjusted = currentDateTime.Date != exifDateTime.Date; bool timeAdjusted = currentDateTime.TimeOfDay != exifDateTime.TimeOfDay; if (dateAdjusted || timeAdjusted) { this.SetDateTimeOffset(exifDateTime); } // At least with several Bushnell Trophy HD and Aggressor models (119677C, 119775C, 119777C) file times are sometimes // indicated an hour before the image taken time during standard time. This is not known to occur during daylight // savings time and does not occur consistently during standard time. It is problematic in the sense time becomes // scrambled, meaning there's no way to detect and correct cases where an image taken time is incorrect because a // daylight-standard transition occurred but the camera hadn't yet been serviced to put its clock on the new time, // and needs to be reported separately as the change of day in images taken just after midnight is not an indicator // of day-month ordering ambiguity in the image taken metadata. bool standardTimeAdjustment = exifDateTime - currentDateTime == TimeSpan.FromHours(1); // snap to metadata time and return the extent of the time adjustment if (standardTimeAdjustment) { return(DateTimeAdjustmentEnum.MetadataDateAndTimeOneHourLater); } if (dateAdjusted && timeAdjusted) { return(DateTimeAdjustmentEnum.MetadataDateAndTimeUsed); } if (dateAdjusted) { return(DateTimeAdjustmentEnum.MetadataDateUsed); } if (timeAdjusted) { return(DateTimeAdjustmentEnum.MetadataTimeUsed); } return(DateTimeAdjustmentEnum.SameFileAndMetadataTime); } catch { return(DateTimeAdjustmentEnum.MetadataNotUsed); } }