[Image Resizer] Add option to remove metadata (#14176)

* Implements option to remove metadata (see #1928)

* Add unit test

* renamed settings switch, update ui text

* Fix exception type, add justification for swallowing exception

* Add unit test to check handling if no metadata is there in targetfile

* Reordered the checkboxes as suggested by @htcfreek

* Reduced size of test image
This commit is contained in:
CleanCodeDeveloper 2021-11-03 19:05:35 +01:00 committed by GitHub
parent 9d9df949ef
commit 9ca32aa3ea
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 166 additions and 4 deletions

View file

@ -28,6 +28,10 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<None Remove="TestMetadataIssue1928.jpg" />
<None Remove="TestMetadataIssue1928_NoMetadata.jpg" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ui\ImageResizerUI.csproj" />
@ -53,6 +57,12 @@
<Content Include="Test.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="TestMetadataIssue1928.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="TestMetadataIssue1928_NoMetadata.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="TestMetadataIssue2447.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

View file

@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ImageResizer.Extensions;
using ImageResizer.Properties;
using ImageResizer.Test;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@ -441,6 +442,50 @@ namespace ImageResizer.Models
Assert.IsTrue(File.Exists(_directory + @"\Directory\Test (Test).png"));
}
[TestMethod]
public void StripMetadata()
{
var operation = new ResizeOperation(
"TestMetadataIssue1928.jpg",
_directory,
Settings(
x =>
{
x.RemoveMetadata = true;
}));
operation.Execute();
AssertEx.Image(
_directory.File(),
image => Assert.IsNull(((BitmapMetadata)image.Frames[0].Metadata).DateTaken));
AssertEx.Image(
_directory.File(),
image => Assert.IsNotNull(((BitmapMetadata)image.Frames[0].Metadata).GetQuerySafe("System.Photo.Orientation")));
}
[TestMethod]
public void StripMetadataWhenNoMetadataPresent()
{
var operation = new ResizeOperation(
"TestMetadataIssue1928_NoMetadata.jpg",
_directory,
Settings(
x =>
{
x.RemoveMetadata = true;
}));
operation.Execute();
AssertEx.Image(
_directory.File(),
image => Assert.IsNull(((BitmapMetadata)image.Frames[0].Metadata).DateTaken));
AssertEx.Image(
_directory.File(),
image => Assert.IsNull(((BitmapMetadata)image.Frames[0].Metadata).GetQuerySafe("System.Photo.Orientation")));
}
private static Settings Settings(Action<Settings> action = null)
{
var settings = new Settings()

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View file

@ -0,0 +1,55 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Windows.Media.Imaging;
namespace ImageResizer.Extensions
{
internal static class BitmapMetadataExtension
{
public static void CopyMetadataPropertyTo(this BitmapMetadata source, BitmapMetadata target, string query)
{
if (source == null || target == null || string.IsNullOrWhiteSpace(query))
{
return;
}
try
{
var value = source.GetQuerySafe(query);
if (value == null)
{
return;
}
target.SetQuery(query, value);
}
catch (InvalidOperationException)
{
// InvalidOperationException is thrown if metadata object is in readonly state.
return;
}
}
public static object GetQuerySafe(this BitmapMetadata metadata, string query)
{
if (metadata == null || string.IsNullOrWhiteSpace(query))
{
return null;
}
try
{
return metadata.GetQuery(query);
}
catch (NotSupportedException)
{
// NotSupportedException is throw if the metadata entry is not preset on the target image (e.g. Orientation not set).
return null;
}
}
}
}

View file

@ -10,6 +10,7 @@ using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ImageResizer.Extensions;
using ImageResizer.Properties;
using ImageResizer.Utilities;
using Microsoft.VisualBasic.FileIO;
@ -82,11 +83,22 @@ namespace ImageResizer.Models
}
}
if (_settings.RemoveMetadata && metadata != null)
{
// strip any metadata that doesn't affect rendering
var newMetadata = new BitmapMetadata(metadata.Format);
metadata.CopyMetadataPropertyTo(newMetadata, "System.Photo.Orientation");
metadata.CopyMetadataPropertyTo(newMetadata, "System.Image.ColorSpace");
metadata = newMetadata;
}
encoder.Frames.Add(
BitmapFrame.Create(
Transform(originalFrame),
thumbnail: null,
metadata, // TODO: Add an option to strip any metadata that doesn't affect rendering (issue #3)
metadata,
colorContexts: null));
}

View file

@ -141,6 +141,15 @@ namespace ImageResizer.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Remove metadata that doesn&apos;t affect rendering.
/// </summary>
public static string Input_RemoveMetadata {
get {
return ResourceManager.GetString("Input_RemoveMetadata", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to R_esize the original pictures (don&apos;t create copies).
/// </summary>

View file

@ -280,4 +280,7 @@
<data name="Open_settings" xml:space="preserve">
<value>Open settings</value>
</data>
<data name="Input_RemoveMetadata" xml:space="preserve">
<value>Remove metadata that doesn't affect rendering</value>
</data>
</root>

View file

@ -30,6 +30,7 @@ namespace ImageResizer.Properties
private int _selectedSizeIndex;
private bool _replace;
private bool _ignoreOrientation;
private bool _removeMetadata;
private int _jpegQualityLevel;
private PngInterlaceOption _pngInterlaceOption;
private TiffCompressOption _tiffCompressOption;
@ -44,6 +45,7 @@ namespace ImageResizer.Properties
ShrinkOnly = false;
Replace = false;
IgnoreOrientation = true;
RemoveMetadata = false;
JpegQualityLevel = 90;
PngInterlaceOption = System.Windows.Media.Imaging.PngInterlaceOption.Default;
TiffCompressOption = System.Windows.Media.Imaging.TiffCompressOption.Default;
@ -280,6 +282,27 @@ namespace ImageResizer.Properties
}
}
/// <summary>
/// Gets or sets a value indicating whether resizing images removes any metadata that doesn't affect rendering.
/// Default is false.
/// </summary>
/// <remarks>
/// Preserved Metadata:
/// System.Photo.Orientation,
/// System.Image.ColorSpace
/// </remarks>
[JsonConverter(typeof(WrappedJsonValueConverter))]
[JsonPropertyName("imageresizer_removeMetadata")]
public bool RemoveMetadata
{
get => _removeMetadata;
set
{
_removeMetadata = value;
NotifyPropertyChanged();
}
}
[JsonConverter(typeof(WrappedJsonValueConverter))]
[JsonPropertyName("imageresizer_jpegQualityLevel")]
public int JpegQualityLevel
@ -423,6 +446,7 @@ namespace ImageResizer.Properties
ShrinkOnly = jsonSettings.ShrinkOnly;
Replace = jsonSettings.Replace;
IgnoreOrientation = jsonSettings.IgnoreOrientation;
RemoveMetadata = jsonSettings.RemoveMetadata;
JpegQualityLevel = jsonSettings.JpegQualityLevel;
PngInterlaceOption = jsonSettings.PngInterlaceOption;
TiffCompressOption = jsonSettings.TiffCompressOption;

View file

@ -122,15 +122,19 @@
<CheckBox Margin="12,4,12,0"
Content="{x:Static p:Resources.Input_ShrinkOnly}"
IsChecked="{Binding Settings.ShrinkOnly}"/>
<CheckBox Margin="12,4,12,0"
Content="{x:Static p:Resources.Input_IgnoreOrientation}"
IsChecked="{Binding Settings.IgnoreOrientation}"/>
<!-- TODO: This option doesn't make much sense when resizing into a directory. We should swap it for an option
to overwrite any files in the directory instead (issue #88) -->
<CheckBox Margin="12,4,12,0"
Content="{x:Static p:Resources.Input_Replace}"
IsChecked="{Binding Settings.Replace}"/>
<CheckBox Margin="12,4,12,0"
Content="{x:Static p:Resources.Input_IgnoreOrientation}"
IsChecked="{Binding Settings.IgnoreOrientation}"/>
Content="{x:Static p:Resources.Input_RemoveMetadata}"
IsChecked="{Binding Settings.RemoveMetadata}"/>
<TextBlock Grid.Column="0"
FontWeight="Bold"