// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. // ReSharper disable InconsistentNaming using System.Buffers.Binary; using System.IO; using System.Text; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; namespace SixLabors.ImageSharp.Tests.Formats.Png { public partial class PngDecoderTests { private const PixelTypes PixelTypes = Tests.PixelTypes.Rgba32 | Tests.PixelTypes.RgbaVector | Tests.PixelTypes.Argb32; public static readonly string[] CommonTestImages = { 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.Rgb24BppTrans, TestImages.Png.GrayAlpha8Bit, TestImages.Png.Gray1BitTrans, TestImages.Png.Bad.ZlibOverflow }; public static readonly string[] TestImages48Bpp = { TestImages.Png.Rgb48Bpp, TestImages.Png.Rgb48BppInterlaced }; public static readonly string[] TestImages64Bpp = { TestImages.Png.Rgba64Bpp, TestImages.Png.Rgb48BppTrans }; public static readonly string[] TestImagesGray16Bit = { TestImages.Png.Gray16Bit, }; public static readonly string[] TestImagesGrayAlpha16Bit = { TestImages.Png.GrayAlpha16Bit, TestImages.Png.GrayTrns16BitInterlaced }; public static readonly string[] TestImagesGray8BitInterlaced = { TestImages.Png.GrayAlpha1BitInterlaced, TestImages.Png.GrayAlpha2BitInterlaced, TestImages.Png.Gray4BitInterlaced, TestImages.Png.GrayAlpha8BitInterlaced }; public static readonly TheoryData RatioFiles = new TheoryData { { TestImages.Png.Splash, 11810, 11810 , PixelResolutionUnit.PixelsPerMeter}, { TestImages.Png.Ratio1x4, 1, 4 , PixelResolutionUnit.AspectRatio}, { TestImages.Png.Ratio4x1, 4, 1, PixelResolutionUnit.AspectRatio } }; [Theory] [WithFileCollection(nameof(CommonTestImages), PixelTypes.Rgba32)] public void Decode(TestImageProvider provider) where TPixel : struct, IPixel { using (Image image = provider.GetImage(new PngDecoder())) { image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact); } } [Theory] [WithFile(TestImages.Png.Interlaced, PixelTypes.Rgba32)] public void Decode_Interlaced_ImageIsCorrect(TestImageProvider provider) where TPixel : struct, IPixel { using (Image image = provider.GetImage(new PngDecoder())) { image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact); } } [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); image.CompareToOriginal(provider, 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())) { image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact); } } [Theory] [WithFileCollection(nameof(TestImagesGray8BitInterlaced), PixelTypes.Rgba32)] public void Decoder_Gray8bitInterlaced(TestImageProvider provider) where TPixel : struct, IPixel { using (Image image = provider.GetImage(new PngDecoder())) { image.DebugSave(provider); image.CompareToOriginal(provider, 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())) { image.DebugSave(provider); image.CompareToOriginal(provider, 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())) { image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact); } } [Theory] [WithFile(TestImages.Png.GrayAlpha8BitInterlaced, PixelTypes)] public void Decoder_CanDecodeGrey8bitWithAlpha(TestImageProvider provider) where TPixel : struct, IPixel { using (Image image = provider.GetImage(new PngDecoder())) { image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact); } } [Theory] [WithFile(TestImages.Png.Splash, PixelTypes)] public void Decoder_IsNotBoundToSinglePixelType(TestImageProvider provider) where TPixel : struct, IPixel { using (Image image = provider.GetImage(new PngDecoder())) { image.DebugSave(provider); image.CompareToOriginal(provider, ImageComparer.Exact); } } [Fact] public void Decode_IgnoreMetadataIsFalse_TextChunckIsRead() { var options = new PngDecoder() { IgnoreMetadata = false }; var testFile = TestFile.Create(TestImages.Png.Blur); using (Image image = testFile.CreateRgba32Image(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 PngDecoder() { IgnoreMetadata = true }; var testFile = TestFile.Create(TestImages.Png.Blur); using (Image image = testFile.CreateRgba32Image(options)) { Assert.Equal(0, image.Metadata.Properties.Count); } } [Fact] public void Decode_TextEncodingSetToUnicode_TextIsReadWithCorrectEncoding() { var options = new PngDecoder() { TextEncoding = Encoding.Unicode }; var testFile = TestFile.Create(TestImages.Png.Blur); using (Image image = testFile.CreateRgba32Image(options)) { Assert.Equal(1, image.Metadata.Properties.Count); Assert.Equal("潓瑦慷敲", image.Metadata.Properties[0].Name); } } [Theory] [InlineData(TestImages.Png.Bpp1, 1)] [InlineData(TestImages.Png.Gray4Bpp, 4)] [InlineData(TestImages.Png.Palette8Bpp, 8)] [InlineData(TestImages.Png.Pd, 24)] [InlineData(TestImages.Png.Blur, 32)] [InlineData(TestImages.Png.Rgb48Bpp, 48)] [InlineData(TestImages.Png.Rgb48BppInterlaced, 48)] public void Identify(string imagePath, int expectedPixelSize) { var testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { Assert.Equal(expectedPixelSize, Image.Identify(stream)?.PixelType?.BitsPerPixel); } } [Theory] [MemberData(nameof(RatioFiles))] public void Decode_VerifyRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) { var testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { var decoder = new PngDecoder(); using (Image image = decoder.Decode(Configuration.Default, stream)) { ImageMetadata meta = image.Metadata; Assert.Equal(xResolution, meta.HorizontalResolution); Assert.Equal(yResolution, meta.VerticalResolution); Assert.Equal(resolutionUnit, meta.ResolutionUnits); } } } [Theory] [MemberData(nameof(RatioFiles))] public void Identify_VerifyRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) { var testFile = TestFile.Create(imagePath); using (var stream = new MemoryStream(testFile.Bytes, false)) { var decoder = new PngDecoder(); IImageInfo image = decoder.Identify(Configuration.Default, stream); ImageMetadata meta = image.Metadata; Assert.Equal(xResolution, meta.HorizontalResolution); Assert.Equal(yResolution, meta.VerticalResolution); Assert.Equal(resolutionUnit, meta.ResolutionUnits); } } } }