diff --git a/src/modules/imageresizer/ui/Extensions/BitmapMetadataExtension.cs b/src/modules/imageresizer/ui/Extensions/BitmapMetadataExtension.cs index 5817ff3cea..d6885c75ee 100644 --- a/src/modules/imageresizer/ui/Extensions/BitmapMetadataExtension.cs +++ b/src/modules/imageresizer/ui/Extensions/BitmapMetadataExtension.cs @@ -3,6 +3,8 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; +using System.Diagnostics; using System.Windows.Media.Imaging; namespace ImageResizer.Extensions @@ -43,7 +45,14 @@ namespace ImageResizer.Extensions try { - return metadata.GetQuery(query); + if (metadata.ContainsQuery(query)) + { + return metadata.GetQuery(query); + } + else + { + return null; + } } catch (NotSupportedException) { @@ -51,5 +60,179 @@ namespace ImageResizer.Extensions return null; } } + + public static void RemoveQuerySafe(this BitmapMetadata metadata, string query) + { + if (metadata == null || string.IsNullOrWhiteSpace(query)) + { + return; + } + + try + { + if (metadata.ContainsQuery(query)) + { + metadata.RemoveQuery(query); + } + } +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception ex) +#pragma warning restore CA1031 // Do not catch general exception types + { + Debug.WriteLine($"Exception while trying to remove metadata entry at position: {query}"); + Debug.WriteLine(ex); + } + } + + public static void SetQuerySafe(this BitmapMetadata metadata, string query, object value) + { + if (metadata == null || string.IsNullOrWhiteSpace(query) || value == null) + { + return; + } + + try + { + metadata.SetQuery(query, value); + } +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception ex) +#pragma warning restore CA1031 // Do not catch general exception types + { + Debug.WriteLine($"Exception while trying to set metadata {value} at position: {query}"); + Debug.WriteLine(ex); + } + } + + /// + /// Gets all metadata + /// Iterates recursively through all metadata + /// + public static List<(string metadataPath, object value)> GetListOfMetadata(this BitmapMetadata metadata) + { + var listOfAllMetadata = new List<(string metadataPath, object value)>(); + + GetMetadataRecursively(metadata, string.Empty); + + return listOfAllMetadata; + + void GetMetadataRecursively(BitmapMetadata metadata, string query) + { + foreach (string relativeQuery in metadata) + { + string absolutePath = query + relativeQuery; + + object metadataQueryReader = null; + + try + { + metadataQueryReader = GetQueryWithPreCheck(metadata, relativeQuery); + } +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception ex) +#pragma warning restore CA1031 // Do not catch general exception types + { + Debug.WriteLine($"Removing corrupt metadata property {absolutePath}. Skipping metadata entry | {ex.Message}"); + Debug.WriteLine(ex); + } + + if (metadataQueryReader != null) + { + listOfAllMetadata.Add((absolutePath, metadataQueryReader)); + } + else + { + Debug.WriteLine($"No metadata found for query {absolutePath}. Skipping empty null entry because its invalid."); + } + + if (metadataQueryReader is BitmapMetadata innerMetadata) + { + GetMetadataRecursively(innerMetadata, absolutePath); + } + } + } + + object GetQueryWithPreCheck(BitmapMetadata metadata, string query) + { + if (metadata == null || string.IsNullOrWhiteSpace(query)) + { + return null; + } + + if (metadata.ContainsQuery(query)) + { + return metadata.GetQuery(query); + } + else + { + return null; + } + } + } + + /// + /// Prints all metadata to debug console + /// + /// + /// Intented for debug only!!! + /// + public static void PrintsAllMetadataToDebugOutput(this BitmapMetadata metadata) + { + if (metadata == null) + { + Debug.WriteLine($"Metadata was null."); + } + + var listOfMetadata = metadata.GetListOfMetadataForDebug(); + foreach (var metadataItem in listOfMetadata) + { + // Debug.WriteLine($"modifiableMetadata.RemoveQuerySafe(\"{metadataItem.metadataPath}\");"); + Debug.WriteLine($"{metadataItem.metadataPath} | {metadataItem.value}"); + } + } + + /// + /// Gets all metadata + /// Iterates recursively through all metadata + /// + /// + /// Intented for debug only!!! + /// + public static List<(string metadataPath, object value)> GetListOfMetadataForDebug(this BitmapMetadata metadata) + { + var listOfAllMetadata = new List<(string metadataPath, object value)>(); + + GetMetadataRecursively(metadata, string.Empty); + + return listOfAllMetadata; + + void GetMetadataRecursively(BitmapMetadata metadata, string query) + { + foreach (string relativeQuery in metadata) + { + string absolutePath = query + relativeQuery; + + object metadataQueryReader = null; + + try + { + metadataQueryReader = metadata.GetQuerySafe(relativeQuery); + listOfAllMetadata.Add((absolutePath, metadataQueryReader)); + } +#pragma warning disable CA1031 // Do not catch general exception types + catch (Exception ex) +#pragma warning restore CA1031 // Do not catch general exception types + { + listOfAllMetadata.Add((absolutePath, $"######## INVALID METADATA: {ex.Message}")); + Debug.WriteLine(ex); + } + + if (metadataQueryReader is BitmapMetadata innerMetadata) + { + GetMetadataRecursively(innerMetadata, absolutePath); + } + } + } + } } } diff --git a/src/modules/imageresizer/ui/Models/ResizeOperation.cs b/src/modules/imageresizer/ui/Models/ResizeOperation.cs index 954c5c09c5..f8b57265bc 100644 --- a/src/modules/imageresizer/ui/Models/ResizeOperation.cs +++ b/src/modules/imageresizer/ui/Models/ResizeOperation.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/ using System; +using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Abstractions; @@ -83,11 +84,36 @@ namespace ImageResizer.Models try { // Detect whether metadata can copied successfully - _ = metadata.Clone(); + var modifiableMetadata = metadata.Clone(); + +#if DEBUG + Debug.WriteLine($"### Processing metadata of file {_file}"); + modifiableMetadata.PrintsAllMetadataToDebugOutput(); +#endif + + // read all metadata and build up metadata object from the scratch. Discard invalid (unreadable/unwritable) metadata. + var newMetadata = new BitmapMetadata(metadata.Format); + var listOfMetadata = modifiableMetadata.GetListOfMetadata(); + foreach (var (metadataPath, value) in listOfMetadata) + { + if (value is BitmapMetadata bitmapMetadata) + { + var innerMetadata = new BitmapMetadata(bitmapMetadata.Format); + newMetadata.SetQuerySafe(metadataPath, innerMetadata); + } + else + { + newMetadata.SetQuerySafe(metadataPath, value); + } + } + + metadata = newMetadata; } - catch (ArgumentException) + catch (ArgumentException ex) { metadata = null; + + Debug.WriteLine(ex); } } @@ -105,9 +131,9 @@ namespace ImageResizer.Models encoder.Frames.Add( BitmapFrame.Create( Transform(originalFrame), - thumbnail: null, + originalFrame.Thumbnail, metadata, - colorContexts: null)); + originalFrame.ColorContexts)); } path = GetDestinationPath(encoder);