From 0e21c6aaa55cc41e3e46d649324c9f7e2509a4cd Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Wed, 26 Feb 2020 17:42:43 +0100 Subject: [PATCH] Add webp lossy tests --- .../Formats/WebP/WebPDecoderTests.cs | 81 +++++++++++------- tests/ImageSharp.Tests/TestImages.cs | 18 ++-- tests/Images/Input/WebP/bike_lossy.webp | Bin 0 -> 9396 bytes 3 files changed, 65 insertions(+), 34 deletions(-) create mode 100644 tests/Images/Input/WebP/bike_lossy.webp diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebPDecoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebPDecoderTests.cs index d31343ef3f..77768639cb 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebPDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebPDecoderTests.cs @@ -17,12 +17,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP public class WebPDecoderTests { + private static WebPDecoder WebpDecoder => new WebPDecoder(); + private static MagickReferenceDecoder ReferenceDecoder => new MagickReferenceDecoder(); + [Theory] [InlineData(Lossless.Lossless1, 1000, 307, 24)] [InlineData(Lossless.Lossless2, 1000, 307, 24)] - [InlineData(Lossy.Alpha.LossyAlpha1, 1000, 307, 24)] - [InlineData(Lossy.Alpha.LossyAlpha2, 1000, 307, 24)] - [InlineData(Animated.Animated1, 400, 400, 24)] + [InlineData(Lossy.Alpha.LossyAlpha1, 1000, 307, 32)] + [InlineData(Lossy.Alpha.LossyAlpha2, 1000, 307, 32)] public void Identify_DetectsCorrectDimensions( string imagePath, int expectedWidth, @@ -41,19 +43,40 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP } [Theory] - [InlineData(Lossy.Alpha.LossyAlpha1, 1000, 307, 24)] - public void DecodeLossyImage_Tmp( - string imagePath, - int expectedWidth, - int expectedHeight, - int expectedBitsPerPixel) + [WithFile(Lossy.Bike, PixelTypes.Rgba32)] + [WithFile(Lossy.LenaIccp, PixelTypes.Rgba32)] + [WithFile(Lossy.Lossy01, PixelTypes.Rgba32)] + [WithFile(Lossy.Lossy02, PixelTypes.Rgba32)] + [WithFile(Lossy.Lossy03, PixelTypes.Rgba32)] + [WithFile(Lossy.Lossy04, PixelTypes.Rgba32)] + [WithFile(Lossy.Lossy05, PixelTypes.Rgba32)] + [WithFile(Lossy.Lossy06, PixelTypes.Rgba32)] + [WithFile(Lossy.Lossy07, PixelTypes.Rgba32)] + [WithFile(Lossy.Lossy08, PixelTypes.Rgba32)] + [WithFile(Lossy.Lossy09, PixelTypes.Rgba32)] + public void WebpDecoder_CanDecode_Lossy(TestImageProvider provider) + where TPixel : struct, IPixel { - var testFile = TestFile.Create(imagePath); - using (var stream = new MemoryStream(testFile.Bytes, false)) + using (Image image = provider.GetImage(WebpDecoder)) { - var image = Image.Load(stream); - Assert.Equal(expectedWidth, image.Width); - Assert.Equal(expectedHeight, image.Height); + image.DebugSave(provider); + image.CompareToOriginal(provider, ReferenceDecoder); + } + } + + [Theory] + [WithFile(Lossy.Alpha.LossyAlpha1, PixelTypes.Rgba32)] + [WithFile(Lossy.Alpha.LossyAlpha2, PixelTypes.Rgba32)] + [WithFile(Lossy.Alpha.LossyAlpha3, PixelTypes.Rgba32)] + [WithFile(Lossy.Alpha.LossyAlpha4, PixelTypes.Rgba32)] + [WithFile(Lossy.Alpha.LossyAlphaNoCompression, PixelTypes.Rgba32)] + public void WebpDecoder_CanDecode_Lossy_WithAlpha(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage(WebpDecoder)) + { + image.DebugSave(provider); + image.CompareToOriginal(provider, ReferenceDecoder); } } @@ -63,10 +86,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP public void WebpDecoder_CanDecode_Lossless_WithoutTransforms(TestImageProvider provider) where TPixel : struct, IPixel { - using (Image image = provider.GetImage(new WebPDecoder())) + using (Image image = provider.GetImage(WebpDecoder)) { image.DebugSave(provider); - image.CompareToOriginal(provider, new MagickReferenceDecoder()); + image.CompareToOriginal(provider, ReferenceDecoder); } } @@ -81,10 +104,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP TestImageProvider provider) where TPixel : struct, IPixel { - using (Image image = provider.GetImage(new WebPDecoder())) + using (Image image = provider.GetImage(WebpDecoder)) { image.DebugSave(provider); - image.CompareToOriginal(provider, new MagickReferenceDecoder()); + image.CompareToOriginal(provider, ReferenceDecoder); } } @@ -97,10 +120,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP public void WebpDecoder_CanDecode_Lossless_WithColorIndexTransform(TestImageProvider provider) where TPixel : struct, IPixel { - using (Image image = provider.GetImage(new WebPDecoder())) + using (Image image = provider.GetImage(WebpDecoder)) { image.DebugSave(provider); - image.CompareToOriginal(provider, new MagickReferenceDecoder()); + image.CompareToOriginal(provider, ReferenceDecoder); } } @@ -110,10 +133,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP public void WebpDecoder_CanDecode_Lossless_WithPredictorTransform(TestImageProvider provider) where TPixel : struct, IPixel { - using (Image image = provider.GetImage(new WebPDecoder())) + using (Image image = provider.GetImage(WebpDecoder)) { image.DebugSave(provider); - image.CompareToOriginal(provider, new MagickReferenceDecoder()); + image.CompareToOriginal(provider, ReferenceDecoder); } } @@ -123,10 +146,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP public void WebpDecoder_CanDecode_Lossless_WithCrossColorTransform(TestImageProvider provider) where TPixel : struct, IPixel { - using (Image image = provider.GetImage(new WebPDecoder())) + using (Image image = provider.GetImage(WebpDecoder)) { image.DebugSave(provider); - image.CompareToOriginal(provider, new MagickReferenceDecoder()); + image.CompareToOriginal(provider, ReferenceDecoder); } } @@ -147,10 +170,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP public void WebpDecoder_CanDecode_Lossless_WithTwoTransforms(TestImageProvider provider) where TPixel : struct, IPixel { - using (Image image = provider.GetImage(new WebPDecoder())) + using (Image image = provider.GetImage(WebpDecoder)) { image.DebugSave(provider); - image.CompareToOriginal(provider, new MagickReferenceDecoder()); + image.CompareToOriginal(provider, ReferenceDecoder); } } @@ -166,10 +189,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP public void WebpDecoder_CanDecode_Lossless_WithThreeTransforms(TestImageProvider provider) where TPixel : struct, IPixel { - using (Image image = provider.GetImage(new WebPDecoder())) + using (Image image = provider.GetImage(WebpDecoder)) { image.DebugSave(provider); - image.CompareToOriginal(provider, new MagickReferenceDecoder()); + image.CompareToOriginal(provider, ReferenceDecoder); } } @@ -181,7 +204,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP public void WebpDecoder_ThrowImageFormatException_OnInvalidImages(TestImageProvider provider) where TPixel : struct, IPixel { - Assert.Throws(() => { using (provider.GetImage(new WebPDecoder())) { } }); + Assert.Throws(() => { using (provider.GetImage(WebpDecoder)) { } }); } } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index aa057c6b85..28613b5c81 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -428,11 +428,18 @@ namespace SixLabors.ImageSharp.Tests public static class Lossy { - public const string SampleWebpOne = "WebP/Lossy/1.webp"; - public const string SampleWebpTwo = "WebP/Lossy/2.webp"; - public const string SampleWebpThree = "WebP/Lossy/3.webp"; - public const string SampleWebpFour = "WebP/Lossy/4.webp"; - public const string SampleWebpFive = "WebP/Lossy/5.webp"; + public const string Bike = "WebP/bike_lossy.webp"; + public const string LenaIccp = "WebP/lossy_iccp.webp"; + public const string VeryShort = "WebP/very_short.webp"; + public const string Lossy01 = "WebP/vp80-01-intra-1400.webp"; + public const string Lossy02 = "WebP/vp80-00-comprehensive-010.webp"; + public const string Lossy03 = "WebP/vp80-01-intra-1417.webp"; + public const string Lossy04 = "WebP/vp80-02-inter-1402.webp"; + public const string Lossy05 = "WebP/vp80-03-segmentation-1401.webp"; + public const string Lossy06 = "WebP/vp80-02-inter-1418.webp"; + public const string Lossy07 = "WebP/vp80-03-segmentation-1403.webp"; + public const string Lossy08 = "WebP/vp80-03-segmentation-1407.webp"; + public const string Lossy09 = "WebP/test.webp"; public static class Alpha { @@ -440,6 +447,7 @@ namespace SixLabors.ImageSharp.Tests public const string LossyAlpha2 = "WebP/lossy_alpha2.webp"; public const string LossyAlpha3 = "WebP/lossy_alpha3.webp"; public const string LossyAlpha4 = "WebP/lossy_alpha4.webp"; + public const string LossyAlphaNoCompression = "WebP/alpha_no_compression.webp"; } } diff --git a/tests/Images/Input/WebP/bike_lossy.webp b/tests/Images/Input/WebP/bike_lossy.webp new file mode 100644 index 0000000000000000000000000000000000000000..9b5d6224530fd9dd9e0f43355ff95fae7a8a3bf9 GIT binary patch literal 9396 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 literal 0 HcmV?d00001