[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:
parent
9d9df949ef
commit
9ca32aa3ea
|
@ -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>
|
||||
|
|
|
@ -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()
|
||||
|
|
BIN
src/modules/imageresizer/tests/TestMetadataIssue1928.jpg
Normal file
BIN
src/modules/imageresizer/tests/TestMetadataIssue1928.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -141,6 +141,15 @@ namespace ImageResizer.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Remove metadata that doesn'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't create copies).
|
||||
/// </summary>
|
||||
|
|
|
@ -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>
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue