// Retrieve and show a single image's metadata in the datagrid, although filter out any metadata whose value is not a valid date.
        private void MetadataExtractorShowImageMetadata()
        {
            this.metadataDictionary = ImageMetadataDictionary.LoadMetadata(this.filePath);
            // If there is no metadata, this is an easy way to inform the user
            if (this.metadataDictionary.Count == 0)
            {
                this.metadataDictionary.Add("Empty", new Timelapse.Util.ImageMetadata("Empty", "No metadata found in the currently displayed image", "Navigate to a displayable image"));
                this.noMetadataAvailable = true;
            }
            else
            {
                this.noMetadataAvailable = false;
            }

            // In order to populate the datagrid, we have to unpack the dictionary as a list containing four values
            List <Tuple <string, string, string, string> > metadataList = new List <Tuple <string, string, string, string> >();

            foreach (KeyValuePair <string, ImageMetadata> metadata in this.metadataDictionary)
            {
                if (metadata.Value == null || metadata.Value.Value == null)
                {
                    // Rare case where a user had a camera with a null Value.Value field
                    continue;
                }

                if (DateTimeHandler.TryParseMetadataDateTaken(metadata.Value.Value.ToString(), out DateTime _))
                {
                    metadataList.Add(new Tuple <string, string, string, string>(metadata.Key, metadata.Value.Directory, metadata.Value.Name, metadata.Value.Value));
                }
            }
            this.AvailableMetadataDataGrid.ItemsSource = metadataList;
        }
Esempio n. 2
0
        // Retrieve and show a single image's metadata in the datagrid
        private void MetadataExtractorShowImageMetadata()
        {
            this.metadataDictionary = ImageMetadataDictionary.LoadMetadata(this.imageFilePath);
            // If there is no metadata, this is an easy way to inform the user
            if (this.metadataDictionary.Count == 0)
            {
                this.metadataDictionary.Add("Empty", new Timelapse.Util.ImageMetadata("Empty", "No metadata found in the chosen image", String.Empty));
            }

            // In order to populate the datagrid, we have to unpack the dictionary as a list containing four values
            List <Tuple <string, string, string, string> > metadataList = new List <Tuple <string, string, string, string> >();

            foreach (KeyValuePair <string, ImageMetadata> metadata in this.metadataDictionary)
            {
                metadataList.Add(new Tuple <string, string, string, string>(metadata.Key, metadata.Value.Directory, metadata.Value.Name, metadata.Value.Value));
            }
            this.dataGrid.ItemsSource = metadataList;
        }
Esempio n. 3
0
        // Try to populate the metadata/data fields specified in metadataOnLoad for the given file, for those metadata fields that exist
        public void TryReadMetadataAndSetMetadataFields(string folderPath, MetadataOnLoad metadataOnLoad)
        {
            try
            {
                Dictionary <string, string>        validatedDictMetadataDatalabel = new Dictionary <string, string>();
                Dictionary <string, ImageMetadata> metadata = new Dictionary <string, ImageMetadata>();

                if (metadataOnLoad.MetadataToolSelected == MetadataToolEnum.MetadataExtractor)
                {
                    // MetadataExtractor - specific code
                    metadata = ImageMetadataDictionary.LoadMetadata(this.GetFilePath(folderPath));
                }
                else // if metadataToolSelected == MetadataToolEnum.ExifTool
                {
                    // ExifTool specific code - we transform the ExifTool results into the same dictionary structure used by the MetadataExtractor
                    metadata.Clear();
                    Dictionary <string, string> exifData = Util.GlobalReferences.TimelapseState.ExifToolManager.FetchExifFrom(this.GetFilePath(folderPath), metadataOnLoad.Tags);

                    foreach (KeyValuePair <string, string> kvp in exifData)
                    {
                        metadata.Add(kvp.Key, new Timelapse.Util.ImageMetadata(String.Empty, kvp.Key, kvp.Value));
                    }
                }

                // At this point, regardless of which metadata tool was used, we have all the information we need
                // to add the metadata to a datafield.
                foreach (KeyValuePair <string, string> kvp in metadataOnLoad.SelectedMetadataDataLabels)
                {
                    // Key is the metadata tag, Value is the data label
                    if (metadata.ContainsKey(kvp.Key))
                    {
                        this.Row.SetField(kvp.Value, metadata[kvp.Key].Value);
                    }
                }
            }
            catch
            {
                // If the above fails, we just keep on going.
            }
        }
        // Populate the database with the metadata for the selected note field
        private async Task <ObservableCollection <KeyValuePair <string, string> > > PopulateAsync(bool?metadataExtractorRBIsChecked)
        {
            // This list will hold key / value pairs that will be bound to the datagrid feedback,
            // which is the way to make those pairs appear in the data grid during background worker progress updates
            ObservableCollection <KeyValuePair <string, string> > keyValueList = new ObservableCollection <KeyValuePair <string, string> >();

            return(await Task.Run(() =>
            {
                // For each row in the database, get the image filename and try to extract the chosen metadata value.
                // Report progress as needed.
                // This tuple list will hold the id, key and value that we will want to update in the database
                List <ColumnTuplesWithWhere> imagesToUpdate = new List <ColumnTuplesWithWhere>();
                TimeZoneInfo imageSetTimeZone = DateTimeHandler.GetNeutralTimeZone();
                int percentDone = 0;

                double totalFiles = this.fileDatabase.CountAllCurrentlySelectedFiles;
                Dictionary <string, ImageMetadata> metadata = new Dictionary <string, ImageMetadata>();
                List <ImageRow> filesToAdjust = new List <ImageRow>();

                // Start up the progress bar, so it shows something as even small data sets will have a delay in it.
                this.Progress.Report(new ProgressBarArguments(percentDone, "Initializing...", true, false));
                Thread.Sleep(Constant.ThrottleValues.RenderingBackoffTime);  // Allows the UI thread to update every now and then

                int metadataUpdateCount = 0;
                for (int imageIndex = 0; imageIndex < totalFiles; ++imageIndex)
                {
                    // Provide feedback if the operation was cancelled during the database update
                    if (Token.IsCancellationRequested == true)
                    {
                        keyValueList.Clear();
                        keyValueList.Add(new KeyValuePair <string, string>("Cancelled", "No changes were made"));
                        return keyValueList;
                    }

                    ImageRow image = this.fileDatabase.FileTable[imageIndex];
                    if (metadataExtractorRBIsChecked == true)
                    {   // MetadataExtractor specific code
                        metadata = ImageMetadataDictionary.LoadMetadata(image.GetFilePath(this.fileDatabase.FolderPath));
                    }
                    else
                    {
                        // ExifTool specific code - note that we transform results into the same dictionary structure used by the MetadataExtractor
                        string[] tags = { this.metadataFieldName };
                        metadata.Clear();
                        Dictionary <string, string> exifData = this.exifTool.FetchExifFrom(image.GetFilePath(this.fileDatabase.FolderPath), tags);
                        if (exifData.ContainsKey(tags[0]))
                        {
                            metadata.Add(tags[0], new Timelapse.Util.ImageMetadata(String.Empty, tags[0], exifData[tags[0]]));
                        }
                    }

                    if (this.ReadyToRefresh())
                    {
                        percentDone = Convert.ToInt32(imageIndex / totalFiles * 100.0);
                        this.Progress.Report(new ProgressBarArguments(percentDone, String.Format("{0}/{1} images. Processing {2}", imageIndex, totalFiles, image.File), true, false));
                        Thread.Sleep(Constant.ThrottleValues.RenderingBackoffTime);  // Allows the UI thread to update every now and then
                    }

                    if (metadata.ContainsKey(this.metadataFieldName) == false)
                    {
                        keyValueList.Add(new KeyValuePair <string, string>(image.File, String.Format("Data field unchanged - file is missing metatdata {0} ", this.metadataFieldName)));

                        // System.Diagnostics.Debug.Print(String.Format("{0}: No metadata", image.File));
                        continue;
                    }
                    metadataUpdateCount++;
                    string metadataValue = metadata[this.metadataFieldName].Value;
                    ColumnTuplesWithWhere imageUpdate;
                    if (DateTimeHandler.TryParseMetadataDateTaken(metadataValue, imageSetTimeZone, out DateTimeOffset metadataDateTime))
                    {
                        image.SetDateTimeOffset(metadataDateTime);
                        imageUpdate = image.GetDateTimeColumnTuples();
                        keyValueList.Add(new KeyValuePair <string, string>(image.File, metadataValue));
                    }
                    else
                    {
                        keyValueList.Add(new KeyValuePair <string, string>(image.File, String.Format("Data field unchanged - '{0}' is not a valid date/time.", metadataValue)));
                        continue;
                    }
                    imagesToUpdate.Add(imageUpdate);
                }
                this.IsAnyDataUpdated = true;
                this.Progress.Report(new ProgressBarArguments(100, String.Format("Writing metadata for the {0}/{1} files that contain this metadata field. Please wait...", metadataUpdateCount, totalFiles), false, true));
                Thread.Sleep(Constant.ThrottleValues.RenderingBackoffTime);  // Allows the UI thread to update every now and then
                this.fileDatabase.UpdateFiles(imagesToUpdate);
                return keyValueList;
            }, this.Token).ConfigureAwait(true));
        }
Esempio n. 5
0
        // Populate the database with the metadata for the selected note field
        private async Task <ObservableCollection <Tuple <string, string, string> > > PopulateAsync(MetadataToolEnum metadataToolSelected)
        {
            // This list will hold key / value pairs that will be bound to the datagrid feedback,
            // which is the way to make those pairs appear in the data grid during background worker progress updates
            ObservableCollection <Tuple <string, string, string> > feedbackData = new ObservableCollection <Tuple <string, string, string> >();

            // if there are no metadata / label pairs, we are done.
            if (this.MetadataGrid.SelectedMetadata.Count == 0)
            {
                // Catch the case where there are no selected pairs, at least for now.
                feedbackData.Clear();
                feedbackData.Add(new Tuple <string, string, string>("Nothing was selected", "", "No changes were made"));
                return(feedbackData);
            }

            return(await Task.Run(() =>
            {
                // For each row in the database, get the image filename and try to extract the chosen metadata value.
                // If we can't decide if we want to leave the data field alone or to clear it depending on the state of the isClearIfNoMetadata (set via the checkbox)
                // Report progress as needed.

                // This tuple list will hold the id, key and value that we will want to update in the database
                List <ColumnTuplesWithWhere> imagesToUpdate = new List <ColumnTuplesWithWhere>();
                TimeZoneInfo imageSetTimeZone = DateTimeHandler.GetNeutralTimeZone();
                int percentDone = 0;

                double totalImages = this.FileDatabase.CountAllCurrentlySelectedFiles;
                Dictionary <string, ImageMetadata> metadata = new Dictionary <string, ImageMetadata>();
                string[] tags = this.MetadataGrid.SelectedTags;// Only needed by ExifTool, but cheap to get
                for (int imageIndex = 0; imageIndex < totalImages; ++imageIndex)
                {
                    // Provide feedback if the operation was cancelled during the database update
                    if (Token.IsCancellationRequested == true)
                    {
                        feedbackData.Clear();
                        feedbackData.Add(new Tuple <string, string, string>("Cancelled", "", "No changes were made"));
                        return feedbackData;
                    }

                    ImageRow image = this.FileDatabase.FileTable[imageIndex];

                    if (metadataToolSelected == MetadataToolEnum.MetadataExtractor)
                    {
                        // MetadataExtractor specific code
                        metadata = ImageMetadataDictionary.LoadMetadata(image.GetFilePath(this.FileDatabase.FolderPath));
                    }
                    else // if metadataToolSelected == MetadataToolEnum.ExifTool
                    {
                        // ExifTool specific code - note that we transform results into the same dictionary structure used by the MetadataExtractor
                        // Unlike MetadataExtractor, ExifTool returns TagName instad of Directory.TagName (I think - but does that mean it would break on duplicate values?
                        metadata.Clear();
                        Dictionary <string, string> exifData = this.MetadataGrid.ExifToolManager.FetchExifFrom(image.GetFilePath(this.FileDatabase.FolderPath), tags);
                        foreach (string tag in tags)
                        {
                            if (exifData.ContainsKey(tag))
                            {
                                metadata.Add(tag, new Timelapse.Util.ImageMetadata(String.Empty, tag, exifData[tag]));
                            }
                        }
                    }
                    // At this point, the metadata Key should be the tag name, rather than Directory.TagName
                    // (see ImageMetadataDiction.LoadDictionary to change it back so the key is the directory.name. I think Exif never returns the directory name, so thats ok too.

                    if (this.ReadyToRefresh())
                    {
                        percentDone = Convert.ToInt32(imageIndex / totalImages * 100.0);
                        this.Progress.Report(new ProgressBarArguments(percentDone, String.Format("{0}/{1} images. Processing {2}", imageIndex, totalImages, image.File), true, false));
                        Thread.Sleep(Constant.ThrottleValues.RenderingBackoffTime);  // Allows the UI thread to update every now and then
                    }

                    string dataLabelToUpdate = "";

                    foreach (KeyValuePair <string, string> kvp in this.MetadataGrid.SelectedMetadata)
                    {
                        string metadataTag = kvp.Key;
                        dataLabelToUpdate = kvp.Value;

                        if (false == metadata.ContainsKey(metadataTag))
                        {
                            // This just skips this metadata as it was not found in the file's metadata
                            // However, we still need to supply feedback and (if the user has asked for that option) to clear the data field
                            if (this.clearIfNoMetadata)
                            {
                                List <ColumnTuple> clearField = new List <ColumnTuple>()
                                {
                                    new ColumnTuple(dataLabelToUpdate, String.Empty)
                                };
                                imagesToUpdate.Add(new ColumnTuplesWithWhere(clearField, image.ID));
                                feedbackData.Add(new Tuple <string, string, string>(image.File, metadataTag, "No metadata found - data field cleared"));
                            }
                            else
                            {
                                feedbackData.Add(new Tuple <string, string, string>(image.File, metadataTag, "No metadata found - data field unchanged"));
                            }
                            continue;
                        }
                        string metadataValue = metadata[metadataTag].Value;
                        ColumnTuplesWithWhere imageUpdate;
                        if (this.useDateMetadataOnly)
                        {
                            if (DateTimeHandler.TryParseMetadataDateTaken(metadataValue, imageSetTimeZone, out DateTimeOffset metadataDateTime))
                            {
                                image.SetDateTimeOffset(metadataDateTime);

                                imageUpdate = image.GetDateTimeColumnTuples();
                                feedbackData.Add(new Tuple <string, string, string>(image.File, metadataTag, metadataValue));
                            }
                            else
                            {
                                feedbackData.Add(new Tuple <string, string, string>(image.File, metadataTag, String.Format("Data field unchanged - '{0}' is not a valid date/time.", metadataValue)));
                                continue;
                            }
                        }
                        else
                        {
                            imageUpdate = new ColumnTuplesWithWhere(new List <ColumnTuple>()
                            {
                                new ColumnTuple(dataLabelToUpdate, metadataValue)
                            }, image.ID);
                            feedbackData.Add(new Tuple <string, string, string>(image.File, metadataTag, metadataValue));
                        }
                        imagesToUpdate.Add(imageUpdate);
                    }
                }
                this.isAnyDataUpdated = true;
                this.Progress.Report(new ProgressBarArguments(100, String.Format("Writing metadata for {0} files. Please wait...", totalImages), false, true));
                Thread.Sleep(Constant.ThrottleValues.RenderingBackoffTime);  // Allows the UI thread to update every now and then
                this.FileDatabase.UpdateFiles(imagesToUpdate);
                return feedbackData;
            }, this.Token).ConfigureAwait(true));
        }
Esempio n. 6
0
        // Populate the database with the metadata for the selected note field
        private async Task <ObservableCollection <KeyValuePair <string, string> > > PopulateAsync(bool?metadataExtractorRBIsChecked)
        {
            // This list will hold key / value pairs that will be bound to the datagrid feedback,
            // which is the way to make those pairs appear in the data grid during background worker progress updates
            ObservableCollection <KeyValuePair <string, string> > keyValueList = new ObservableCollection <KeyValuePair <string, string> >();

            return(await Task.Run(() =>
            {
                // For each row in the database, get the image filename and try to extract the chosen metadata value.
                // If we can't decide if we want to leave the data field alone or to clear it depending on the state of the isClearIfNoMetadata (set via the checkbox)
                // Report progress as needed.
                // This tuple list will hold the id, key and value that we will want to update in the database
                string dataLabelToUpdate = this.dataLabelByLabel[this.dataFieldLabel];
                List <ColumnTuplesWithWhere> imagesToUpdate = new List <ColumnTuplesWithWhere>();
                TimeZoneInfo imageSetTimeZone = this.fileDatabase.ImageSet.GetSystemTimeZone();
                int percentDone = 0;

                double totalImages = this.fileDatabase.CountAllCurrentlySelectedFiles;
                Dictionary <string, ImageMetadata> metadata = new Dictionary <string, ImageMetadata>();
                for (int imageIndex = 0; imageIndex < totalImages; ++imageIndex)
                {
                    // Provide feedback if the operation was cancelled during the database update
                    if (Token.IsCancellationRequested == true)
                    {
                        keyValueList.Clear();
                        keyValueList.Add(new KeyValuePair <string, string>("Cancelled", "No changes were made"));
                        return keyValueList;
                    }

                    ImageRow image = this.fileDatabase.FileTable[imageIndex];
                    if (metadataExtractorRBIsChecked == true)
                    {   // MetadataExtractor specific code
                        metadata = ImageMetadataDictionary.LoadMetadata(image.GetFilePath(this.fileDatabase.FolderPath));
                    }
                    else
                    {
                        // ExifTool specific code - note that we transform results into the same dictionary structure used by the MetadataExtractor
                        string[] tags = { this.metadataFieldName };
                        metadata.Clear();
                        Dictionary <string, string> exifData = this.exifTool.FetchExifFrom(image.GetFilePath(this.fileDatabase.FolderPath), tags);
                        if (exifData.ContainsKey(tags[0]))
                        {
                            metadata.Add(tags[0], new Timelapse.Util.ImageMetadata(String.Empty, tags[0], exifData[tags[0]]));
                        }
                    }

                    if (this.ReadyToRefresh())
                    {
                        percentDone = Convert.ToInt32(imageIndex / totalImages * 100.0);
                        this.Progress.Report(new ProgressBarArguments(percentDone, String.Format("{0}/{1} images. Processing {2}", imageIndex, totalImages, image.File), true, false));
                        Thread.Sleep(Constant.ThrottleValues.RenderingBackoffTime);  // Allows the UI thread to update every now and then
                    }

                    if (metadata.ContainsKey(this.metadataFieldName) == false)
                    {
                        if (this.clearIfNoMetadata)
                        {
                            // Clear the data field if there is no metadata...
                            if (dataLabelToUpdate == Constant.DatabaseColumn.DateTime)
                            {
                                image.SetDateTimeOffsetFromFileInfo(this.fileDatabase.FolderPath);
                                imagesToUpdate.Add(image.GetDateTimeColumnTuples());
                                keyValueList.Add(new KeyValuePair <string, string>(image.File, "No metadata found - date/time reread from file"));
                            }
                            else
                            {
                                List <ColumnTuple> clearField = new List <ColumnTuple>()
                                {
                                    new ColumnTuple(this.dataLabelByLabel[this.dataFieldLabel], String.Empty)
                                };
                                imagesToUpdate.Add(new ColumnTuplesWithWhere(clearField, image.ID));
                                keyValueList.Add(new KeyValuePair <string, string>(image.File, "No metadata found - data field is cleared"));
                            }
                        }
                        else
                        {
                            keyValueList.Add(new KeyValuePair <string, string>(image.File, "No metadata found - data field remains unaltered"));
                        }

                        continue;
                    }

                    string metadataValue = metadata[this.metadataFieldName].Value;
                    ColumnTuplesWithWhere imageUpdate;
                    if (dataLabelToUpdate == Constant.DatabaseColumn.DateTime)
                    {
                        if (DateTimeHandler.TryParseMetadataDateTaken(metadataValue, imageSetTimeZone, out DateTimeOffset metadataDateTime))
                        {
                            image.SetDateTimeOffset(metadataDateTime);
                            imageUpdate = image.GetDateTimeColumnTuples();
                            keyValueList.Add(new KeyValuePair <string, string>(image.File, metadataValue));
                        }
                        else
                        {
                            keyValueList.Add(new KeyValuePair <string, string>(image.File, String.Format("'{0}' - data field remains unaltered - not a valid date/time.", metadataValue)));
                            continue;
                        }
                    }
                    else
                    {
                        imageUpdate = new ColumnTuplesWithWhere(new List <ColumnTuple>()
                        {
                            new ColumnTuple(dataLabelToUpdate, metadataValue)
                        }, image.ID);
                        keyValueList.Add(new KeyValuePair <string, string>(image.File, metadataValue));
                    }
                    imagesToUpdate.Add(imageUpdate);
                }
                this.IsAnyDataUpdated = true;
                this.Progress.Report(new ProgressBarArguments(100, String.Format("Writing metadata for {0} files. Please wait...", totalImages), false, true));
                Thread.Sleep(Constant.ThrottleValues.RenderingBackoffTime);  // Allows the UI thread to update every now and then
                this.fileDatabase.UpdateFiles(imagesToUpdate);
                return keyValueList;
            }, this.Token).ConfigureAwait(true));
        }