diff --git a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs index 0036280a8..64dad23bc 100644 --- a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs +++ b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs @@ -9,11 +9,11 @@ namespace SixLabors.ImageSharp.Formats.Png public sealed class PngConfigurationModule : IConfigurationModule { /// - public void Configure(Configuration config) + public void Configure(Configuration configuration) { - config.ImageFormatsManager.SetEncoder(ImageFormats.Png, new PngEncoder()); - config.ImageFormatsManager.SetDecoder(ImageFormats.Png, new PngDecoder()); - config.ImageFormatsManager.AddImageFormatDetector(new PngImageFormatDetector()); + configuration.ImageFormatsManager.SetEncoder(ImageFormats.Png, new PngEncoder()); + configuration.ImageFormatsManager.SetDecoder(ImageFormats.Png, new PngDecoder()); + configuration.ImageFormatsManager.AddImageFormatDetector(new PngImageFormatDetector()); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 02fcd1643..348b3b185 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -21,65 +21,83 @@ namespace SixLabors.ImageSharp.Tests private const PixelTypes PixelTypes = Tests.PixelTypes.Rgba32 | Tests.PixelTypes.RgbaVector | Tests.PixelTypes.Argb32; // Contains the png marker, IHDR and pHYs chunks of a 1x1 pixel 32bit png 1 a single black pixel. - private static byte[] raw1x1PngIHDRAndpHYs = + private static readonly byte[] raw1x1PngIHDRAndpHYs = { // PNG Identifier 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, - + // IHDR 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, // IHDR CRC - 0x90, 0x77, 0x53, 0xDE, + 0x90, 0x77, 0x53, 0xDE, // pHYS - 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01, + 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01, // pHYS CRC 0xC7, 0x6F, 0xA8, 0x64 }; // Contains the png marker, IDAT and IEND chunks of a 1x1 pixel 32bit png 1 a single black pixel. - private static byte[] raw1x1PngIDATAndIEND = + private static readonly byte[] raw1x1PngIDATAndIEND = { // IDAT 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x18, 0x57, 0x63, 0x60, 0x60, 0x60, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x01, + 0x00, 0x04, 0x00, 0x01, + // IDAT CRC - 0x5C, 0xCD, 0xFF, 0x69, + 0x5C, 0xCD, 0xFF, 0x69, // IEND 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, - 0x4E, 0x44, + 0x4E, 0x44, + // IEND CRC 0xAE, 0x42, 0x60, 0x82 }; public static readonly string[] CommonTestImages = - { - TestImages.Png.Splash, - TestImages.Png.Indexed, - TestImages.Png.FilterVar, - TestImages.Png.Bad.ChunkLength1, - TestImages.Png.Bad.CorruptedChunk, + { + TestImages.Png.Splash, + TestImages.Png.Indexed, + TestImages.Png.FilterVar, + TestImages.Png.Bad.ChunkLength1, + TestImages.Png.Bad.CorruptedChunk, + + TestImages.Png.VimImage1, + TestImages.Png.VersioningImage1, + TestImages.Png.VersioningImage2, + + TestImages.Png.SnakeGame, + TestImages.Png.Banner7Adam7InterlaceMode, + TestImages.Png.Banner8Index, + + TestImages.Png.Bad.ChunkLength2, + TestImages.Png.VimImage2, + }; - TestImages.Png.VimImage1, - TestImages.Png.VersioningImage1, - TestImages.Png.VersioningImage2, - TestImages.Png.SnakeGame, - TestImages.Png.Banner7Adam7InterlaceMode, - TestImages.Png.Banner8Index, + public static readonly string[] TestImages48Bpp = + { + TestImages.Png.Rgb48Bpp, + TestImages.Png.Rgb48BppInterlaced + }; - TestImages.Png.Bad.ChunkLength2, - TestImages.Png.VimImage2, - }; + public static readonly string[] TestImages64Bpp = +{ + TestImages.Png.Rgba64Bpp, + }; + public static readonly string[] TestImagesGray16Bit = + { + TestImages.Png.Gray16Bit, + }; - public static readonly string[] TestImages48Bpp = - { - TestImages.Png.Rgb48Bpp, - TestImages.Png.Rgb48BppInterlaced - }; + public static readonly string[] TestImagesGrayAlpha16Bit = + { + TestImages.Png.GrayAlpha16Bit, + TestImages.Png.GrayTrns16Bit + }; // This is a workaround for Mono-s decoder being incompatible with ours and GDI+. // We shouldn't mix these with the Interleaved cases (which are also failing with Mono System.Drawing). Let's go AAA! @@ -142,20 +160,66 @@ namespace SixLabors.ImageSharp.Tests } } - // TODO: We need to decode these into Rgba64 properly, and do 'CompareToOriginal' in a Rgba64 mode! (See #285) - [Theory(Skip = "Skipped for now until we can update the reference images from libpng samples.")] - [WithFileCollection(nameof(TestImages48Bpp), PixelTypes.Rgba32)] + [Theory] + [WithFileCollection(nameof(TestImages48Bpp), PixelTypes.Rgb48)] public void Decode_48Bpp(TestImageProvider provider) where TPixel : struct, IPixel { using (Image image = provider.GetImage(new PngDecoder())) { - image.DebugSave(provider); + var encoder = new PngEncoder { ColorType = PngColorType.Rgb, BitDepth = PngBitDepth.Bit16 }; - // Workaround a bug in mono-s System.Drawing PNG decoder. It can't deal with 48Bpp png-s :( - if (!TestEnvironment.IsLinux && !TestEnvironment.IsMono) + if (!SkipVerification(provider)) { - image.CompareToOriginal(provider, ImageComparer.Exact); + image.VerifyEncoder(provider, "png", null, encoder, customComparer: ImageComparer.Exact); + } + } + } + + [Theory] + [WithFileCollection(nameof(TestImages64Bpp), PixelTypes.Rgba64)] + public void Decode_64Bpp(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage(new PngDecoder())) + { + var encoder = new PngEncoder { ColorType = PngColorType.RgbWithAlpha, BitDepth = PngBitDepth.Bit16 }; + + if (!SkipVerification(provider)) + { + image.VerifyEncoder(provider, "png", null, encoder, customComparer: ImageComparer.Exact); + } + } + } + + [Theory] + [WithFileCollection(nameof(TestImagesGray16Bit), PixelTypes.Rgb48)] + public void Decode_Gray16Bit(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage(new PngDecoder())) + { + var encoder = new PngEncoder { ColorType = PngColorType.Grayscale, BitDepth = PngBitDepth.Bit16 }; + + if (!SkipVerification(provider)) + { + image.VerifyEncoder(provider, "png", null, encoder, customComparer: ImageComparer.Exact); + } + } + } + + [Theory] + [WithFileCollection(nameof(TestImagesGrayAlpha16Bit), PixelTypes.Rgba64)] + public void Decode_GrayAlpha16Bit(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage(new PngDecoder())) + { + var encoder = new PngEncoder { ColorType = PngColorType.GrayscaleWithAlpha, BitDepth = PngBitDepth.Bit16 }; + + if (!SkipVerification(provider)) + { + image.VerifyEncoder(provider, "png", null, encoder, customComparer: ImageComparer.Exact); } } } @@ -233,7 +297,7 @@ namespace SixLabors.ImageSharp.Tests [InlineData(TestImages.Png.Rgb48BppInterlaced, 48)] public void DetectPixelSize(string imagePath, int expectedPixelSize) { - TestFile testFile = TestFile.Create(imagePath); + var testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); @@ -257,10 +321,7 @@ namespace SixLabors.ImageSharp.Tests var decoder = new PngDecoder(); - ImageFormatException exception = Assert.Throws(() => - { - decoder.Decode(null, memStream); - }); + ImageFormatException exception = Assert.Throws(() => decoder.Decode(null, memStream)); Assert.Equal($"CRC Error. PNG {chunkName} chunk is corrupt!", exception.Message); } diff --git a/tests/ImageSharp.Tests/TestFile.cs b/tests/ImageSharp.Tests/TestFile.cs index b736dce20..089249e21 100644 --- a/tests/ImageSharp.Tests/TestFile.cs +++ b/tests/ImageSharp.Tests/TestFile.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Tests /// // ReSharper disable once InconsistentNaming private static readonly Lazy inputImagesDirectory = new Lazy(() => TestEnvironment.InputImagesDirectoryFullPath); - + /// /// The image (lazy initialized value) /// @@ -74,9 +74,10 @@ namespace SixLabors.ImageSharp.Tests private Image Image => this.image ?? (this.image = ImageSharp.Image.Load(this.Bytes)); /// + /// Gets the input image directory. /// private static string InputImagesDirectory => inputImagesDirectory.Value; - + /// /// Gets the full qualified path to the input test file. /// diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index d261f9497..d965b01d7 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -27,7 +27,11 @@ namespace SixLabors.ImageSharp.Tests public const string Palette8Bpp = "Png/palette-8bpp.png"; public const string Bpp1 = "Png/bpp1.png"; public const string Gray4Bpp = "Png/gray_4bpp.png"; + public const string Gray16Bit = "Png/gray-16.png"; + public const string GrayAlpha16Bit = "Png/gray-alpha-16.png"; + public const string GrayTrns16Bit = "Png/gray-16-tRNS.png"; public const string Rgb48Bpp = "Png/rgb-48bpp.png"; + public const string Rgba64Bpp = "Png/rgb-16-alpha.png"; public const string CalliphoraPartial = "Png/CalliphoraPartial.png"; public const string CalliphoraPartialGrayscale = "Png/CalliphoraPartialGrayscale.png"; public const string Bike = "Png/Bike.png"; @@ -126,7 +130,7 @@ namespace SixLabors.ImageSharp.Tests }; } - public class Issues + public static class Issues { public const string CriticalEOF214 = "Jpg/issues/Issue214-CriticalEOF.jpg"; public const string MissingFF00ProgressiveGirl159 = "Jpg/issues/Issue159-MissingFF00-Progressive-Girl.jpg"; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs index 4dcfcd4b7..9de791ab6 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs @@ -80,11 +80,12 @@ namespace SixLabors.ImageSharp.Tests stride = 1; } - TPixel[] c = { - NamedColors.HotPink, - NamedColors.Blue - }; - + TPixel[] c = + { + NamedColors.HotPink, + NamedColors.Blue + }; + for (int y = top; y < bottom; y++) { int p = 0; @@ -112,10 +113,11 @@ namespace SixLabors.ImageSharp.Tests int top = 0; int bottom = pixels.Height / 2; int stride = pixels.Width / 6; - TPixel[] c = { - NamedColors.Black, - NamedColors.White - }; + TPixel[] c = + { + NamedColors.Black, + NamedColors.White + }; int p = 0; for (int y = top; y < bottom; y++) diff --git a/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs b/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs index a8f7acb40..a051e577d 100644 --- a/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs +++ b/tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs @@ -56,6 +56,8 @@ namespace SixLabors.ImageSharp.Tests Bgra32 = 1 << 20, + Rgb48 = 1 << 21, + // TODO: Add multi-flag entries by rules defined in PackedPixelConverterHelper // "All" is handled as a separate, individual case instead of using bitwise OR diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs index 6bebf3887..f62237936 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Tests private static Lazy configuration = new Lazy(CreateDefaultConfiguration); internal static Configuration Configuration => configuration.Value; - + internal static IImageDecoder GetReferenceDecoder(string filePath) { IImageFormat format = GetImageFormat(filePath); @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests internal static IImageFormat GetImageFormat(string filePath) { string extension = Path.GetExtension(filePath); - + IImageFormat format = Configuration.ImageFormatsManager.FindFormatByFileExtension(extension); return format; } @@ -60,11 +60,10 @@ namespace SixLabors.ImageSharp.Tests if (!IsLinux) { - configuration.ConfigureCodecs( - ImageFormats.Png, - SystemDrawingReferenceDecoder.Instance, - SystemDrawingReferenceEncoder.Png, - new PngImageFormatDetector()); + // System.Drawing on Windows can decode 48bit and 64bit pngs but + // it doesn't preserve the accuracy we require for comparison. + // This makes CompareToOriginal method non-useful. + configuration.Configure(new PngConfigurationModule()); configuration.ConfigureCodecs( ImageFormats.Bmp, diff --git a/tests/Images/Input/Png/gray-16-tRNS.png b/tests/Images/Input/Png/gray-16-tRNS.png new file mode 100644 index 000000000..599db9b73 --- /dev/null +++ b/tests/Images/Input/Png/gray-16-tRNS.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f150b76c824e4870322d6564a214a8ef00b4b100d5fd6f5ba551f6f242005bcc +size 684 diff --git a/tests/Images/Input/Png/gray-16.png b/tests/Images/Input/Png/gray-16.png new file mode 100644 index 000000000..599db9b73 --- /dev/null +++ b/tests/Images/Input/Png/gray-16.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f150b76c824e4870322d6564a214a8ef00b4b100d5fd6f5ba551f6f242005bcc +size 684 diff --git a/tests/Images/Input/Png/gray-alpha-16.png b/tests/Images/Input/Png/gray-alpha-16.png new file mode 100644 index 000000000..7c186cb34 --- /dev/null +++ b/tests/Images/Input/Png/gray-alpha-16.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dc3444bd2457c7c3414359bed6f05d1a5b84c08186b3b54a9ab4a4c503775f63 +size 859 diff --git a/tests/Images/Input/Png/rgb-16-alpha.png b/tests/Images/Input/Png/rgb-16-alpha.png new file mode 100644 index 000000000..25098f0e7 --- /dev/null +++ b/tests/Images/Input/Png/rgb-16-alpha.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3ad2152ee0de2aaa8745757a9ff5e90a30b6e84365bd90f450286eb2734bd78a +size 1377