// 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);
            }
        }
Example #2
0
        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);
            }
        }