From 507b2f8554281087322c02d49379f847345223a7 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 27 Jun 2018 00:30:23 +0200 Subject: [PATCH] using MagickReferenceDecoder everywhere, added ReferenceDecoderBenchmarks --- .../TestUtilities/ImagingTestCaseUtility.cs | 6 +- .../ReferenceCodecs/MagickReferenceDecoder.cs | 4 +- .../SystemDrawingReferenceEncoder.cs | 2 + .../TestUtilities/TestEnvironment.Formats.cs | 41 +++----- .../TestUtilities/TestEnvironment.cs | 8 +- .../TestUtilities/TestImageExtensions.cs | 19 ++-- .../Tests/ReferenceDecoderBenchmarks.cs | 96 +++++++++++++++++++ 7 files changed, 131 insertions(+), 45 deletions(-) create mode 100644 tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 2c4eb6c33c..65b32e0880 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -146,7 +146,6 @@ namespace SixLabors.ImageSharp.Tests appendSourceFileOrDescription); } - /// /// Encodes image by the format matching the required extension, than saves it to the recommended output file. /// @@ -154,7 +153,9 @@ namespace SixLabors.ImageSharp.Tests /// The image instance /// The requested extension /// Optional encoder - /// /// A boolean indicating whether to append to the test output file name. + /// A value indicating whether to append the pixel type to the test output file name + /// A boolean indicating whether to append to the test output file name. + /// Additional information to append to the test output file name public string SaveTestOutputFile( Image image, string extension = null, @@ -176,6 +177,7 @@ namespace SixLabors.ImageSharp.Tests { image.Save(stream, encoder); } + return path; } diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index 9b209137bc..8cfc2472f5 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -15,6 +15,8 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { public class MagickReferenceDecoder : IImageDecoder { + public static MagickReferenceDecoder Instance { get; } = new MagickReferenceDecoder(); + public Image Decode(Configuration configuration, Stream stream) where TPixel : struct, IPixel { @@ -40,7 +42,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs } else { - throw new NotImplementedException(); + throw new InvalidOperationException(); } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs index 9123336955..46dae17a11 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceEncoder.cs @@ -20,6 +20,8 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs public static SystemDrawingReferenceEncoder Png { get; } = new SystemDrawingReferenceEncoder(ImageFormat.Png); + public static SystemDrawingReferenceEncoder Bmp { get; } = new SystemDrawingReferenceEncoder(ImageFormat.Bmp); + public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs index 566c22342c..30067ec2dc 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs @@ -14,9 +14,9 @@ namespace SixLabors.ImageSharp.Tests { public static partial class TestEnvironment { - private static Lazy configuration = new Lazy(CreateDefaultConfiguration); + private static readonly Lazy ConfigurationLazy = new Lazy(CreateDefaultConfiguration); - internal static Configuration Configuration => configuration.Value; + internal static Configuration Configuration => ConfigurationLazy.Value; internal static IImageDecoder GetReferenceDecoder(string filePath) { @@ -52,36 +52,25 @@ namespace SixLabors.ImageSharp.Tests private static Configuration CreateDefaultConfiguration() { - var configuration = new Configuration( - new PngConfigurationModule(), + var cfg = new Configuration( new JpegConfigurationModule(), new GifConfigurationModule() ); - if (!IsLinux) - { - // TODO: 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.ConfigureCodecs( - ImageFormats.Png, - SystemDrawingReferenceDecoder.Instance, - SystemDrawingReferenceEncoder.Png, - new PngImageFormatDetector()); + // Magick codecs should work on all + cfg.ConfigureCodecs( + ImageFormats.Png, + MagickReferenceDecoder.Instance, + SystemDrawingReferenceEncoder.Png, + new PngImageFormatDetector()); - configuration.ConfigureCodecs( - ImageFormats.Bmp, - SystemDrawingReferenceDecoder.Instance, - SystemDrawingReferenceEncoder.Png, - new PngImageFormatDetector()); - } - else - { - configuration.Configure(new PngConfigurationModule()); - configuration.Configure(new BmpConfigurationModule()); - } + cfg.ConfigureCodecs( + ImageFormats.Bmp, + MagickReferenceDecoder.Instance, + SystemDrawingReferenceEncoder.Bmp, + new BmpImageFormatDetector()); - return configuration; + return cfg; } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs index 9a41e66025..f0b7329989 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs @@ -21,9 +21,9 @@ namespace SixLabors.ImageSharp.Tests private const string ToolsDirectoryRelativePath = @"tests\Images\External\tools"; - private static Lazy solutionDirectoryFullPath = new Lazy(GetSolutionDirectoryFullPathImpl); + private static readonly Lazy SolutionDirectoryFullPathLazy = new Lazy(GetSolutionDirectoryFullPathImpl); - private static Lazy runsOnCi = new Lazy( + private static readonly Lazy RunsOnCiLazy = new Lazy( () => { bool isCi; @@ -41,9 +41,9 @@ namespace SixLabors.ImageSharp.Tests /// /// Gets a value indicating whether test execution runs on CI. /// - internal static bool RunsOnCI => runsOnCi.Value; + internal static bool RunsOnCI => RunsOnCiLazy.Value; - internal static string SolutionDirectoryFullPath => solutionDirectoryFullPath.Value; + internal static string SolutionDirectoryFullPath => SolutionDirectoryFullPathLazy.Value; private static string GetSolutionDirectoryFullPathImpl() { diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 79a0071ff0..a1f97afb9c 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -499,16 +499,18 @@ namespace SixLabors.ImageSharp.Tests public static Image CompareToOriginal( this Image image, - ITestImageProvider provider) + ITestImageProvider provider, + IImageDecoder referenceDecoder = null) where TPixel : struct, IPixel { - return CompareToOriginal(image, provider, ImageComparer.Tolerant()); + return CompareToOriginal(image, provider, ImageComparer.Tolerant(), referenceDecoder); } public static Image CompareToOriginal( this Image image, ITestImageProvider provider, - ImageComparer comparer) + ImageComparer comparer, + IImageDecoder referenceDecoder = null) where TPixel : struct, IPixel { string path = TestImageProvider.GetFilePathOrNull(provider); @@ -519,15 +521,8 @@ namespace SixLabors.ImageSharp.Tests var testFile = TestFile.Create(path); - IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(path); - IImageFormat format = TestEnvironment.GetImageFormat(path); - IImageDecoder defaultDecoder = Configuration.Default.ImageFormatsManager.FindDecoder(format); - - //if (referenceDecoder.GetType() == defaultDecoder.GetType()) - //{ - // throw new InvalidOperationException($"Can't use CompareToOriginal(): no actual reference decoder registered for {format.Name}"); - //} - + referenceDecoder = referenceDecoder ?? TestEnvironment.GetReferenceDecoder(path); + using (var original = Image.Load(testFile.Bytes, referenceDecoder)) { comparer.VerifySimilarity(original, image); diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs new file mode 100644 index 0000000000..724c2e4144 --- /dev/null +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs @@ -0,0 +1,96 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; + +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests +{ + public class ReferenceDecoderBenchmarks + { + private ITestOutputHelper Output { get; } + + public const string SkipBenchmarks = +#if false + "Benchmark, enable manually!"; +#else + null; +#endif + + public const int DefaultExecutionCount = 50; + + public static readonly string[] PngBenchmarkFiles = + { + TestImages.Png.CalliphoraPartial, + TestImages.Png.Kaboom, + TestImages.Png.Bike, + TestImages.Png.Splash, + TestImages.Png.SplashInterlaced + }; + + public static readonly string[] BmpBenchmarkFiles = + { + TestImages.Bmp.NegHeight, + TestImages.Bmp.Car, + TestImages.Bmp.V5Header + }; + + public ReferenceDecoderBenchmarks(ITestOutputHelper output) + { + this.Output = output; + } + + [Theory(Skip = SkipBenchmarks)] + [WithFile(TestImages.Png.Kaboom, PixelTypes.Rgba32)] + public void BenchmarkMagickPngDecoder(TestImageProvider provider) + where TPixel : struct, IPixel + { + this.BenckmarkDecoderImpl(PngBenchmarkFiles, new MagickReferenceDecoder(), $@"Magick Decode Png"); + } + + [Theory(Skip = SkipBenchmarks)] + [WithFile(TestImages.Png.Kaboom, PixelTypes.Rgba32)] + public void BenchmarkSystemDrawingPngDecoder(TestImageProvider provider) + where TPixel : struct, IPixel + { + this.BenckmarkDecoderImpl(PngBenchmarkFiles, new SystemDrawingReferenceDecoder(), $@"System.Drawing Decode Png"); + } + + [Theory(Skip = SkipBenchmarks)] + [WithFile(TestImages.Png.Kaboom, PixelTypes.Rgba32)] + public void BenchmarkMagickBmpDecoder(TestImageProvider provider) + where TPixel : struct, IPixel + { + this.BenckmarkDecoderImpl(BmpBenchmarkFiles, new MagickReferenceDecoder(), $@"Magick Decode Bmp"); + } + + [Theory(Skip = SkipBenchmarks)] + [WithFile(TestImages.Png.Kaboom, PixelTypes.Rgba32)] + public void BenchmarkSystemDrawingBmpDecoder(TestImageProvider provider) + where TPixel : struct, IPixel + { + this.BenckmarkDecoderImpl(BmpBenchmarkFiles, new SystemDrawingReferenceDecoder(), $@"System.Drawing Decode Bmp"); + } + + private void BenckmarkDecoderImpl(IEnumerable testFiles, IImageDecoder decoder, string info, int times = DefaultExecutionCount) + { + var measure = new MeasureFixture(this.Output); + measure.Measure(times, + () => + { + foreach (string testFile in testFiles) + { + Image image = TestFile.Create(testFile).CreateImage(decoder); + image.Dispose(); + } + }, + info); + } + } +} \ No newline at end of file