[Image Resizer]Try to recover metadata even when the metadata data structure is invalid (#14914)

* metadata.Clone() fails also for situations where we still can recover metadata

metadata.Clone() is also an expensive operation (deep copy) and it is not necessary anymore as we build up the metadata object from scratch anyway

* If an exception is throw here something is seriously wrong with the metadata structure

We take all metadata we have read so far an write it to the resized image

* add log statement

* Adjust test written for #2447 as we are able to copy the metadata now

* Improve documentation
This commit is contained in:
CleanCodeDeveloper 2021-12-10 14:54:05 +01:00 committed by GitHub
parent 1e0033166f
commit 9152ea8f1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 11 deletions

View File

@ -33,7 +33,7 @@ namespace ImageResizer.Models
} }
[TestMethod] [TestMethod]
public void ExecuteCopiesFrameMetadataExceptWhenMetadataCannotBeCloned() public void ExecuteCopiesFrameMetadataEvenWhenMetadataCannotBeCloned()
{ {
var operation = new ResizeOperation("TestMetadataIssue2447.jpg", _directory, Settings()); var operation = new ResizeOperation("TestMetadataIssue2447.jpg", _directory, Settings());
@ -41,7 +41,7 @@ namespace ImageResizer.Models
AssertEx.Image( AssertEx.Image(
_directory.File(), _directory.File(),
image => Assert.IsNull(((BitmapMetadata)image.Frames[0].Metadata).CameraModel)); image => Assert.IsNotNull(((BitmapMetadata)image.Frames[0].Metadata).CameraModel));
} }
[TestMethod] [TestMethod]

View File

@ -105,14 +105,31 @@ namespace ImageResizer.Extensions
} }
/// <summary> /// <summary>
/// Gets all metadata /// Gets all metadata.
/// Iterates recursively through all metadata /// Iterates recursively through metadata and adds valid items to a list while skipping invalid data items.
/// </summary> /// </summary>
/// <remarks>
/// Invalid data items are items which throw an exception when reading the data with metadata.GetQuery(...).
/// Sometimes Metadata collections are improper closed and cause an exception on IEnumerator.MoveNext(). In this case, we return all data items which were successfully collected so far.
/// </remarks>
/// <returns>
/// metadata path and metadata value of all successfully read data items.
/// </returns>
public static List<(string metadataPath, object value)> GetListOfMetadata(this BitmapMetadata metadata) public static List<(string metadataPath, object value)> GetListOfMetadata(this BitmapMetadata metadata)
{ {
var listOfAllMetadata = new List<(string metadataPath, object value)>(); var listOfAllMetadata = new List<(string metadataPath, object value)>();
GetMetadataRecursively(metadata, string.Empty); try
{
GetMetadataRecursively(metadata, string.Empty);
}
#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 iterate recursively over metadata. We were able to read {listOfAllMetadata.Count} metadata entries.");
Debug.WriteLine(ex);
}
return listOfAllMetadata; return listOfAllMetadata;
@ -202,7 +219,17 @@ namespace ImageResizer.Extensions
{ {
var listOfAllMetadata = new List<(string metadataPath, object value)>(); var listOfAllMetadata = new List<(string metadataPath, object value)>();
GetMetadataRecursively(metadata, string.Empty); try
{
GetMetadataRecursively(metadata, string.Empty);
}
#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 iterate recursively over metadata. We were able to read {listOfAllMetadata.Count} metadata entries.");
Debug.WriteLine(ex);
}
return listOfAllMetadata; return listOfAllMetadata;

View File

@ -83,17 +83,14 @@ namespace ImageResizer.Models
{ {
try try
{ {
// Detect whether metadata can copied successfully
var modifiableMetadata = metadata.Clone();
#if DEBUG #if DEBUG
Debug.WriteLine($"### Processing metadata of file {_file}"); Debug.WriteLine($"### Processing metadata of file {_file}");
modifiableMetadata.PrintsAllMetadataToDebugOutput(); metadata.PrintsAllMetadataToDebugOutput();
#endif #endif
// read all metadata and build up metadata object from the scratch. Discard invalid (unreadable/unwritable) metadata. // read all metadata and build up metadata object from the scratch. Discard invalid (unreadable/unwritable) metadata.
var newMetadata = new BitmapMetadata(metadata.Format); var newMetadata = new BitmapMetadata(metadata.Format);
var listOfMetadata = modifiableMetadata.GetListOfMetadata(); var listOfMetadata = metadata.GetListOfMetadata();
foreach (var (metadataPath, value) in listOfMetadata) foreach (var (metadataPath, value) in listOfMetadata)
{ {
if (value is BitmapMetadata bitmapMetadata) if (value is BitmapMetadata bitmapMetadata)