diff --git a/src/ImageSharp.Formats.Png/IPngDecoderOptions.cs b/src/ImageSharp.Formats.Png/IPngDecoderOptions.cs new file mode 100644 index 000000000..f60f3d1cd --- /dev/null +++ b/src/ImageSharp.Formats.Png/IPngDecoderOptions.cs @@ -0,0 +1,20 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System.Text; + + /// + /// Encapsulates the png decoder options. + /// + public interface IPngDecoderOptions : IDecoderOptions + { + /// + /// Gets the encoding that should be used when reading text chunks. + /// + Encoding TextEncoding { get; } + } +} diff --git a/src/ImageSharp.Formats.Png/PngDecoder.cs b/src/ImageSharp.Formats.Png/PngDecoder.cs index 9aab6673a..c731ae448 100644 --- a/src/ImageSharp.Formats.Png/PngDecoder.cs +++ b/src/ImageSharp.Formats.Png/PngDecoder.cs @@ -34,7 +34,9 @@ namespace ImageSharp.Formats public void Decode(Image image, Stream stream, IDecoderOptions options) where TColor : struct, IPixel { - new PngDecoderCore().Decode(image, stream); + IPngDecoderOptions pngOptions = PngDecoderOptions.Create(options); + + new PngDecoderCore(pngOptions).Decode(image, stream); } } } diff --git a/src/ImageSharp.Formats.Png/PngDecoderCore.cs b/src/ImageSharp.Formats.Png/PngDecoderCore.cs index 47b09d5ff..4a5ad3648 100644 --- a/src/ImageSharp.Formats.Png/PngDecoderCore.cs +++ b/src/ImageSharp.Formats.Png/PngDecoderCore.cs @@ -64,6 +64,11 @@ namespace ImageSharp.Formats /// private readonly char[] chars = new char[4]; + /// + /// The decoder options. + /// + private readonly IPngDecoderOptions options; + /// /// Reusable crc for validating chunks. /// @@ -120,6 +125,15 @@ namespace ImageSharp.Formats ColorTypes.Add((int)PngColorType.RgbWithAlpha, new byte[] { 8 }); } + /// + /// Initializes a new instance of the class. + /// + /// The decoder options. + public PngDecoderCore(IPngDecoderOptions options) + { + this.options = options ?? new PngDecoderOptions(); + } + /// /// Gets or sets the png color type /// @@ -763,6 +777,11 @@ namespace ImageSharp.Formats private void ReadTextChunk(Image image, byte[] data, int length) where TColor : struct, IPixel { + if (this.options.IgnoreMetadata) + { + return; + } + int zeroIndex = 0; for (int i = 0; i < length; i++) @@ -774,8 +793,8 @@ namespace ImageSharp.Formats } } - string name = Encoding.Unicode.GetString(data, 0, zeroIndex); - string value = Encoding.Unicode.GetString(data, zeroIndex + 1, length - zeroIndex - 1); + string name = this.options.TextEncoding.GetString(data, 0, zeroIndex); + string value = this.options.TextEncoding.GetString(data, zeroIndex + 1, length - zeroIndex - 1); image.MetaData.Properties.Add(new ImageProperty(name, value)); } diff --git a/src/ImageSharp.Formats.Png/PngDecoderOptions.cs b/src/ImageSharp.Formats.Png/PngDecoderOptions.cs new file mode 100644 index 000000000..07c0c2739 --- /dev/null +++ b/src/ImageSharp.Formats.Png/PngDecoderOptions.cs @@ -0,0 +1,62 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Formats +{ + using System.Text; + + /// + /// Encapsulates the png decoder options. + /// + public sealed class PngDecoderOptions : DecoderOptions, IPngDecoderOptions + { + private static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); + + /// + /// Initializes a new instance of the class. + /// + public PngDecoderOptions() + { + this.InitializeWithDefaults(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The options for the decoder. + private PngDecoderOptions(IDecoderOptions options) + : base(options) + { + this.InitializeWithDefaults(); + } + + /// + /// Gets or sets the encoding that should be used when reading text chunks. + /// + public Encoding TextEncoding { get; set; } + + /// + /// Converts the options to a instance with a cast + /// or by creating a new instance with the specfied options. + /// + /// The options for the decoder. + /// The options for the png decoder. + internal static IPngDecoderOptions Create(IDecoderOptions options) + { + IPngDecoderOptions pngOptions = options as IPngDecoderOptions; + if (pngOptions != null) + { + return pngOptions; + } + + return new PngDecoderOptions(options); + } + + private void InitializeWithDefaults() + { + this.TextEncoding = DefaultEncoding; + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderCoreTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderCoreTests.cs new file mode 100644 index 000000000..3ee2ea826 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderCoreTests.cs @@ -0,0 +1,66 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests +{ + using System.Text; + using Xunit; + + using ImageSharp.Formats; + + public class PngDecoderCoreTests + { + [Fact] + public void Decode_IgnoreMetadataIsFalse_TextChunckIsRead() + { + var options = new PngDecoderOptions() + { + IgnoreMetadata = false + }; + + TestFile testFile = TestFile.Create(TestImages.Png.Blur); + + using (Image image = new Image(testFile.FilePath, options)) + { + Assert.Equal(1, image.MetaData.Properties.Count); + Assert.Equal("Software", image.MetaData.Properties[0].Name); + Assert.Equal("paint.net 4.0.6", image.MetaData.Properties[0].Value); + } + } + + [Fact] + public void Decode_IgnoreMetadataIsTrue_TextChunksAreIgnored() + { + var options = new PngDecoderOptions() + { + IgnoreMetadata = true + }; + + TestFile testFile = TestFile.Create(TestImages.Png.Blur); + + using (Image image = new Image(testFile.FilePath, options)) + { + Assert.Equal(0, image.MetaData.Properties.Count); + } + } + + [Fact] + public void Decode_TextEncodingSetToUnicode_TextIsReadWithCorrectEncoding() + { + var options = new PngDecoderOptions() + { + TextEncoding = Encoding.Unicode + }; + + TestFile testFile = TestFile.Create(TestImages.Png.Blur); + + using (Image image = new Image(testFile.FilePath, options)) + { + Assert.Equal(1, image.MetaData.Properties.Count); + Assert.Equal("潓瑦慷敲", image.MetaData.Properties[0].Name); + } + } + } +} \ No newline at end of file