From 45edceb0bc8ca6781d77409779cc95a7da813b6a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 14 Apr 2019 08:01:38 +1000 Subject: [PATCH 1/3] Use more accuracy when calculating variance. Fix #866 (#874) * Use more accuracy when calculating variance. Fix #866 * Add unit tests * Add test that fails with old image. * Make IFrameQuantizer IDisposable * Update GifEncoderCore.cs --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 24 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 7 +- .../FrameQuantizerBase{TPixel}.cs | 5 + .../Quantization/IFrameQuantizer{TPixel}.cs | 3 +- .../Quantization/QuantizeProcessor.cs | 2 +- .../Quantization/WuFrameQuantizer{TPixel}.cs | 416 ++++++++++-------- .../Quantization/WuQuantizerTests.cs | 168 +++++++ tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Png/low-variance.png | Bin 0 -> 7844 bytes 9 files changed, 422 insertions(+), 204 deletions(-) create mode 100644 tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs create mode 100644 tests/Images/Input/Png/low-variance.png diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index e5a5463eb..12a515cca 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -95,8 +95,11 @@ namespace SixLabors.ImageSharp.Formats.Gif bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global; // Quantize the image returning a palette. - QuantizedFrame quantized = - this.quantizer.CreateFrameQuantizer(image.GetConfiguration()).QuantizeFrame(image.Frames.RootFrame); + QuantizedFrame quantized = null; + using (IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(image.GetConfiguration())) + { + quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame); + } // Get the number of bits. this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); @@ -133,7 +136,6 @@ namespace SixLabors.ImageSharp.Formats.Gif // Clean up. quantized?.Dispose(); - quantized = null; // TODO: Write extension etc stream.WriteByte(GifConstants.EndIntroducer); @@ -158,7 +160,8 @@ namespace SixLabors.ImageSharp.Formats.Gif } else { - using (QuantizedFrame paletteQuantized = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration()).QuantizeFrame(frame)) + using (IFrameQuantizer palleteFrameQuantizer = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration())) + using (QuantizedFrame paletteQuantized = palleteFrameQuantizer.QuantizeFrame(frame)) { this.WriteImageData(paletteQuantized, stream); } @@ -181,14 +184,17 @@ namespace SixLabors.ImageSharp.Formats.Gif if (previousFrame != null && previousMeta.ColorTableLength != frameMetadata.ColorTableLength && frameMetadata.ColorTableLength > 0) { - quantized = this.quantizer.CreateFrameQuantizer( - image.GetConfiguration(), - frameMetadata.ColorTableLength).QuantizeFrame(frame); + using (IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(image.GetConfiguration(), frameMetadata.ColorTableLength)) + { + quantized = frameQuantizer.QuantizeFrame(frame); + } } else { - quantized = this.quantizer.CreateFrameQuantizer(image.GetConfiguration()) - .QuantizeFrame(frame); + using (IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(image.GetConfiguration())) + { + quantized = frameQuantizer.QuantizeFrame(frame); + } } } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 9818e6cf1..7415b0753 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -243,8 +243,11 @@ namespace SixLabors.ImageSharp.Formats.Png } // Create quantized frame returning the palette and set the bit depth. - quantized = this.quantizer.CreateFrameQuantizer(image.GetConfiguration()) - .QuantizeFrame(image.Frames.RootFrame); + using (IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(image.GetConfiguration())) + { + quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame); + } + byte quantizedBits = (byte)ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); bits = Math.Max(bits, quantizedBits); diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index a70cfb660..f23343f6d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -98,6 +98,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization return quantizedFrame; } + /// + public virtual void Dispose() + { + } + /// /// Execute the first pass through the pixels in the image to create the palette. /// diff --git a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs index 50fdb5b58..f0b68b3a0 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Dithering; @@ -10,7 +11,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Provides methods to allow the execution of the quantization process on an image frame. /// /// The pixel format. - public interface IFrameQuantizer + public interface IFrameQuantizer : IDisposable where TPixel : struct, IPixel { /// diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs index 8da89bf94..e99f504b4 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - IFrameQuantizer executor = this.Quantizer.CreateFrameQuantizer(configuration); + using (IFrameQuantizer executor = this.Quantizer.CreateFrameQuantizer(configuration)) using (QuantizedFrame quantized = executor.QuantizeFrame(source)) { int paletteCount = quantized.Palette.Length - 1; diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 44df226cf..1f1513adf 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -11,6 +11,8 @@ using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; +// TODO: Isn't an AOS ("array of structures") layout more efficient & more readable than SOA ("structure of arrays") for this particular use case? +// (T, R, G, B, A, M2) could be grouped together! Investigate a ColorMoment struct. namespace SixLabors.ImageSharp.Processing.Processors.Quantization { /// @@ -36,20 +38,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization internal sealed class WuFrameQuantizer : FrameQuantizerBase where TPixel : struct, IPixel { - // TODO: The WuFrameQuantizer code is rising several questions: - // - Do we really need to ALWAYS allocate the whole table of size TableLength? (~ 2471625 * sizeof(long) * 5 bytes ) JS. I'm afraid so. - // - Isn't an AOS ("array of structures") layout more efficient & more readable than SOA ("structure of arrays") for this particular use case? - // (T, R, G, B, A, M2) could be grouped together! - // - It's a frequently used class, we need tests! (So we can optimize safely.) There are tests in the original!!! We should just adopt them! - // https://github.com/JeremyAnsel/JeremyAnsel.ColorQuant/blob/master/JeremyAnsel.ColorQuant/JeremyAnsel.ColorQuant.Tests/WuColorQuantizerTests.cs + // The following two variables determine the amount of bits to preserve when calculating the histogram. + // Reducing the value of these numbers the granularity of the color maps produced, making it much faster + // and using much less memory but potentially less accurate. Current results are very good though! /// - /// The index bits. + /// The index bits. 6 in original code. /// private const int IndexBits = 5; /// - /// The index alpha bits. Keep separate for now to allow easy adjustment. + /// The index alpha bits. 3 in original code. /// private const int IndexAlphaBits = 5; @@ -64,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization private const int IndexAlphaCount = (1 << IndexAlphaBits) + 1; /// - /// The table length. Now 1185921. + /// The table length. Now 1185921. originally 2471625. /// private const int TableLength = IndexCount * IndexCount * IndexCount * IndexAlphaCount; @@ -96,7 +95,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Moment of c^2*P(c). /// - private IMemoryOwner m2; + private IMemoryOwner m2; /// /// Color space tag. @@ -149,28 +148,27 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Guard.NotNull(image, nameof(image)); MemoryAllocator memoryAllocator = image.MemoryAllocator; - try - { - this.vwt = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); - this.vmr = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); - this.vmg = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); - this.vmb = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); - this.vma = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); - this.m2 = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); - this.tag = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); - - return base.QuantizeFrame(image); - } - finally - { - this.vwt?.Dispose(); - this.vmr?.Dispose(); - this.vmg?.Dispose(); - this.vmb?.Dispose(); - this.vma?.Dispose(); - this.m2?.Dispose(); - this.tag?.Dispose(); - } + this.vwt = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); + this.vmr = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); + this.vmg = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); + this.vmb = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); + this.vma = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); + this.m2 = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); + this.tag = memoryAllocator.Allocate(TableLength, AllocationOptions.Clean); + + return base.QuantizeFrame(image); + } + + /// + public override void Dispose() + { + this.vwt?.Dispose(); + this.vmr?.Dispose(); + this.vmg?.Dispose(); + this.vmb?.Dispose(); + this.vma?.Dispose(); + this.m2?.Dispose(); + this.tag?.Dispose(); } internal TPixel[] AotGetPalette() => this.GetPalette(); @@ -275,9 +273,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int GetPaletteIndex(int r, int g, int b, int a) { - return (r << ((IndexBits * 2) + IndexAlphaBits)) + (r << (IndexBits + IndexAlphaBits + 1)) - + (g << (IndexBits + IndexAlphaBits)) + (r << (IndexBits * 2)) + (r << (IndexBits + 1)) - + (g << IndexBits) + ((r + g + b) << IndexAlphaBits) + r + g + b + a; + return (r << ((IndexBits * 2) + IndexAlphaBits)) + + (r << (IndexBits + IndexAlphaBits + 1)) + + (g << (IndexBits + IndexAlphaBits)) + + (r << (IndexBits * 2)) + + (r << (IndexBits + 1)) + + (g << IndexBits) + + ((r + g + b) << IndexAlphaBits) + + r + g + b + a; } /// @@ -288,26 +291,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The result. private static float Volume(ref Box cube, Span moment) { - return moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A1)] - - moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A0)] - - moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A1)] - + moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A0)] - - moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A1)] - + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)] - + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)] - - moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)] - - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A1)] - + moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A0)] - + moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A1)] - - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)] - + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A1)] - - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)] - - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)] - + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)]; + return moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMax, cube.AMax)] + - moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMax, cube.AMin)] + - moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, cube.AMax)] + + moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, cube.AMin)] + - moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, cube.AMax)] + + moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, cube.AMin)] + + moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMax)] + - moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMin)] + - moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, cube.AMax)] + + moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, cube.AMin)] + + moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMax)] + - moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMin)] + + moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMax)] + - moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMin)] + - moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMax)] + + moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMin)]; } /// - /// Computes part of Volume(cube, moment) that doesn't depend on r1, g1, or b1 (depending on direction). + /// Computes part of Volume(cube, moment) that doesn't depend on RMax, GMax, BMax, or AMax (depending on direction). /// /// The cube. /// The direction. @@ -319,47 +322,47 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { // Red case 3: - return -moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A1)] - + moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A0)] - + moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A1)] - - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)] - + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A1)] - - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)] - - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)] - + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)]; + return -moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, cube.AMax)] + + moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, cube.AMin)] + + moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMax)] + - moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMin)] + + moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMax)] + - moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMin)] + - moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMax)] + + moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMin)]; // Green case 2: - return -moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A1)] - + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)] - + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)] - - moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)] - + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A1)] - - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)] - - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)] - + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)]; + return -moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, cube.AMax)] + + moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, cube.AMin)] + + moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMax)] + - moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMin)] + + moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMax)] + - moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMin)] + - moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMax)] + + moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMin)]; // Blue case 1: - return -moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A1)] - + moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A0)] - + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)] - - moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)] - + moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A1)] - - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)] - - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)] - + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)]; + return -moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, cube.AMax)] + + moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, cube.AMin)] + + moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMax)] + - moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMin)] + + moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMax)] + - moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMin)] + - moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMax)] + + moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMin)]; // Alpha case 0: - return -moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A0)] - + moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A0)] - + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)] - - moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)] - + moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A0)] - - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)] - - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)] - + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)]; + return -moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMax, cube.AMin)] + + moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, cube.AMin)] + + moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, cube.AMin)] + - moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMin)] + + moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, cube.AMin)] + - moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMin)] + - moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMin)] + + moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMin)]; default: throw new ArgumentOutOfRangeException(nameof(direction)); @@ -367,7 +370,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } /// - /// Computes remainder of Volume(cube, moment), substituting position for r1, g1, or b1 (depending on direction). + /// Computes remainder of Volume(cube, moment), substituting position for RMax, GMax, BMax, or AMax (depending on direction). /// /// The cube. /// The direction. @@ -380,47 +383,47 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { // Red case 3: - return moment[GetPaletteIndex(position, cube.G1, cube.B1, cube.A1)] - - moment[GetPaletteIndex(position, cube.G1, cube.B1, cube.A0)] - - moment[GetPaletteIndex(position, cube.G1, cube.B0, cube.A1)] - + moment[GetPaletteIndex(position, cube.G1, cube.B0, cube.A0)] - - moment[GetPaletteIndex(position, cube.G0, cube.B1, cube.A1)] - + moment[GetPaletteIndex(position, cube.G0, cube.B1, cube.A0)] - + moment[GetPaletteIndex(position, cube.G0, cube.B0, cube.A1)] - - moment[GetPaletteIndex(position, cube.G0, cube.B0, cube.A0)]; + return moment[GetPaletteIndex(position, cube.GMax, cube.BMax, cube.AMax)] + - moment[GetPaletteIndex(position, cube.GMax, cube.BMax, cube.AMin)] + - moment[GetPaletteIndex(position, cube.GMax, cube.BMin, cube.AMax)] + + moment[GetPaletteIndex(position, cube.GMax, cube.BMin, cube.AMin)] + - moment[GetPaletteIndex(position, cube.GMin, cube.BMax, cube.AMax)] + + moment[GetPaletteIndex(position, cube.GMin, cube.BMax, cube.AMin)] + + moment[GetPaletteIndex(position, cube.GMin, cube.BMin, cube.AMax)] + - moment[GetPaletteIndex(position, cube.GMin, cube.BMin, cube.AMin)]; // Green case 2: - return moment[GetPaletteIndex(cube.R1, position, cube.B1, cube.A1)] - - moment[GetPaletteIndex(cube.R1, position, cube.B1, cube.A0)] - - moment[GetPaletteIndex(cube.R1, position, cube.B0, cube.A1)] - + moment[GetPaletteIndex(cube.R1, position, cube.B0, cube.A0)] - - moment[GetPaletteIndex(cube.R0, position, cube.B1, cube.A1)] - + moment[GetPaletteIndex(cube.R0, position, cube.B1, cube.A0)] - + moment[GetPaletteIndex(cube.R0, position, cube.B0, cube.A1)] - - moment[GetPaletteIndex(cube.R0, position, cube.B0, cube.A0)]; + return moment[GetPaletteIndex(cube.RMax, position, cube.BMax, cube.AMax)] + - moment[GetPaletteIndex(cube.RMax, position, cube.BMax, cube.AMin)] + - moment[GetPaletteIndex(cube.RMax, position, cube.BMin, cube.AMax)] + + moment[GetPaletteIndex(cube.RMax, position, cube.BMin, cube.AMin)] + - moment[GetPaletteIndex(cube.RMin, position, cube.BMax, cube.AMax)] + + moment[GetPaletteIndex(cube.RMin, position, cube.BMax, cube.AMin)] + + moment[GetPaletteIndex(cube.RMin, position, cube.BMin, cube.AMax)] + - moment[GetPaletteIndex(cube.RMin, position, cube.BMin, cube.AMin)]; // Blue case 1: - return moment[GetPaletteIndex(cube.R1, cube.G1, position, cube.A1)] - - moment[GetPaletteIndex(cube.R1, cube.G1, position, cube.A0)] - - moment[GetPaletteIndex(cube.R1, cube.G0, position, cube.A1)] - + moment[GetPaletteIndex(cube.R1, cube.G0, position, cube.A0)] - - moment[GetPaletteIndex(cube.R0, cube.G1, position, cube.A1)] - + moment[GetPaletteIndex(cube.R0, cube.G1, position, cube.A0)] - + moment[GetPaletteIndex(cube.R0, cube.G0, position, cube.A1)] - - moment[GetPaletteIndex(cube.R0, cube.G0, position, cube.A0)]; + return moment[GetPaletteIndex(cube.RMax, cube.GMax, position, cube.AMax)] + - moment[GetPaletteIndex(cube.RMax, cube.GMax, position, cube.AMin)] + - moment[GetPaletteIndex(cube.RMax, cube.GMin, position, cube.AMax)] + + moment[GetPaletteIndex(cube.RMax, cube.GMin, position, cube.AMin)] + - moment[GetPaletteIndex(cube.RMin, cube.GMax, position, cube.AMax)] + + moment[GetPaletteIndex(cube.RMin, cube.GMax, position, cube.AMin)] + + moment[GetPaletteIndex(cube.RMin, cube.GMin, position, cube.AMax)] + - moment[GetPaletteIndex(cube.RMin, cube.GMin, position, cube.AMin)]; // Alpha case 0: - return moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, position)] - - moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, position)] - - moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, position)] - + moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, position)] - - moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, position)] - + moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, position)] - + moment[GetPaletteIndex(cube.R0, cube.G0, cube.B1, position)] - - moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, position)]; + return moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMax, position)] + - moment[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, position)] + - moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, position)] + + moment[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, position)] + - moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, position)] + + moment[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, position)] + + moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, position)] + - moment[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, position)]; default: throw new ArgumentOutOfRangeException(nameof(direction)); @@ -440,7 +443,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Span vmgSpan = this.vmg.GetSpan(); Span vmbSpan = this.vmb.GetSpan(); Span vmaSpan = this.vma.GetSpan(); - Span m2Span = this.m2.GetSpan(); + Span m2Span = this.m2.GetSpan(); // Build up the 3-D color histogram // Loop through each row @@ -489,34 +492,34 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Span vmgSpan = this.vmg.GetSpan(); Span vmbSpan = this.vmb.GetSpan(); Span vmaSpan = this.vma.GetSpan(); - Span m2Span = this.m2.GetSpan(); + Span m2Span = this.m2.GetSpan(); using (IMemoryOwner volume = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) using (IMemoryOwner volumeR = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) using (IMemoryOwner volumeG = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) using (IMemoryOwner volumeB = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) using (IMemoryOwner volumeA = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) - using (IMemoryOwner volume2 = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) + using (IMemoryOwner volume2 = memoryAllocator.Allocate(IndexCount * IndexAlphaCount)) using (IMemoryOwner area = memoryAllocator.Allocate(IndexAlphaCount)) using (IMemoryOwner areaR = memoryAllocator.Allocate(IndexAlphaCount)) using (IMemoryOwner areaG = memoryAllocator.Allocate(IndexAlphaCount)) using (IMemoryOwner areaB = memoryAllocator.Allocate(IndexAlphaCount)) using (IMemoryOwner areaA = memoryAllocator.Allocate(IndexAlphaCount)) - using (IMemoryOwner area2 = memoryAllocator.Allocate(IndexAlphaCount)) + using (IMemoryOwner area2 = memoryAllocator.Allocate(IndexAlphaCount)) { Span volumeSpan = volume.GetSpan(); Span volumeRSpan = volumeR.GetSpan(); Span volumeGSpan = volumeG.GetSpan(); Span volumeBSpan = volumeB.GetSpan(); Span volumeASpan = volumeA.GetSpan(); - Span volume2Span = volume2.GetSpan(); + Span volume2Span = volume2.GetSpan(); Span areaSpan = area.GetSpan(); Span areaRSpan = areaR.GetSpan(); Span areaGSpan = areaG.GetSpan(); Span areaBSpan = areaB.GetSpan(); Span areaASpan = areaA.GetSpan(); - Span area2Span = area2.GetSpan(); + Span area2Span = area2.GetSpan(); for (int r = 1; r < IndexCount; r++) { @@ -543,7 +546,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization long lineG = 0; long lineB = 0; long lineA = 0; - float line2 = 0; + double line2 = 0; for (int a = 1; a < IndexAlphaCount; a++) { @@ -592,35 +595,35 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The cube. /// The . - private float Variance(ref Box cube) + private double Variance(ref Box cube) { float dr = Volume(ref cube, this.vmr.GetSpan()); float dg = Volume(ref cube, this.vmg.GetSpan()); float db = Volume(ref cube, this.vmb.GetSpan()); float da = Volume(ref cube, this.vma.GetSpan()); - Span m2Span = this.m2.GetSpan(); - - float xx = - m2Span[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A1)] - - m2Span[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A0)] - - m2Span[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A1)] - + m2Span[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A0)] - - m2Span[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A1)] - + m2Span[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)] - + m2Span[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)] - - m2Span[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A0)] - - m2Span[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A1)] - + m2Span[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A0)] - + m2Span[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A1)] - - m2Span[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A0)] - + m2Span[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A1)] - - m2Span[GetPaletteIndex(cube.R0, cube.G0, cube.B1, cube.A0)] - - m2Span[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)] - + m2Span[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)]; + Span m2Span = this.m2.GetSpan(); + + double moment = + m2Span[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMax, cube.AMax)] + - m2Span[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMax, cube.AMin)] + - m2Span[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, cube.AMax)] + + m2Span[GetPaletteIndex(cube.RMax, cube.GMax, cube.BMin, cube.AMin)] + - m2Span[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, cube.AMax)] + + m2Span[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMax, cube.AMin)] + + m2Span[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMax)] + - m2Span[GetPaletteIndex(cube.RMax, cube.GMin, cube.BMin, cube.AMin)] + - m2Span[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, cube.AMax)] + + m2Span[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMax, cube.AMin)] + + m2Span[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMax)] + - m2Span[GetPaletteIndex(cube.RMin, cube.GMax, cube.BMin, cube.AMin)] + + m2Span[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMax)] + - m2Span[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMax, cube.AMin)] + - m2Span[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMax)] + + m2Span[GetPaletteIndex(cube.RMin, cube.GMin, cube.BMin, cube.AMin)]; var vector = new Vector4(dr, dg, db, da); - return xx - (Vector4.Dot(vector, vector) / Volume(ref cube, this.vwt.GetSpan())); + return moment - (Vector4.Dot(vector, vector) / Volume(ref cube, this.vwt.GetSpan())); } /// @@ -714,10 +717,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization float wholeA = Volume(ref set1, this.vma.GetSpan()); float wholeW = Volume(ref set1, this.vwt.GetSpan()); - float maxr = this.Maximize(ref set1, 3, set1.R0 + 1, set1.R1, out int cutr, wholeR, wholeG, wholeB, wholeA, wholeW); - float maxg = this.Maximize(ref set1, 2, set1.G0 + 1, set1.G1, out int cutg, wholeR, wholeG, wholeB, wholeA, wholeW); - float maxb = this.Maximize(ref set1, 1, set1.B0 + 1, set1.B1, out int cutb, wholeR, wholeG, wholeB, wholeA, wholeW); - float maxa = this.Maximize(ref set1, 0, set1.A0 + 1, set1.A1, out int cuta, wholeR, wholeG, wholeB, wholeA, wholeW); + float maxr = this.Maximize(ref set1, 3, set1.RMin + 1, set1.RMax, out int cutr, wholeR, wholeG, wholeB, wholeA, wholeW); + float maxg = this.Maximize(ref set1, 2, set1.GMin + 1, set1.GMax, out int cutg, wholeR, wholeG, wholeB, wholeA, wholeW); + float maxb = this.Maximize(ref set1, 1, set1.BMin + 1, set1.BMax, out int cutb, wholeR, wholeG, wholeB, wholeA, wholeW); + float maxa = this.Maximize(ref set1, 0, set1.AMin + 1, set1.AMax, out int cuta, wholeR, wholeG, wholeB, wholeA, wholeW); int dir; @@ -743,48 +746,48 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization dir = 0; } - set2.R1 = set1.R1; - set2.G1 = set1.G1; - set2.B1 = set1.B1; - set2.A1 = set1.A1; + set2.RMax = set1.RMax; + set2.GMax = set1.GMax; + set2.BMax = set1.BMax; + set2.AMax = set1.AMax; switch (dir) { // Red case 3: - set2.R0 = set1.R1 = cutr; - set2.G0 = set1.G0; - set2.B0 = set1.B0; - set2.A0 = set1.A0; + set2.RMin = set1.RMax = cutr; + set2.GMin = set1.GMin; + set2.BMin = set1.BMin; + set2.AMin = set1.AMin; break; // Green case 2: - set2.G0 = set1.G1 = cutg; - set2.R0 = set1.R0; - set2.B0 = set1.B0; - set2.A0 = set1.A0; + set2.GMin = set1.GMax = cutg; + set2.RMin = set1.RMin; + set2.BMin = set1.BMin; + set2.AMin = set1.AMin; break; // Blue case 1: - set2.B0 = set1.B1 = cutb; - set2.R0 = set1.R0; - set2.G0 = set1.G0; - set2.A0 = set1.A0; + set2.BMin = set1.BMax = cutb; + set2.RMin = set1.RMin; + set2.GMin = set1.GMin; + set2.AMin = set1.AMin; break; // Alpha case 0: - set2.A0 = set1.A1 = cuta; - set2.R0 = set1.R0; - set2.G0 = set1.G0; - set2.B0 = set1.B0; + set2.AMin = set1.AMax = cuta; + set2.RMin = set1.RMin; + set2.GMin = set1.GMin; + set2.BMin = set1.BMin; break; } - set1.Volume = (set1.R1 - set1.R0) * (set1.G1 - set1.G0) * (set1.B1 - set1.B0) * (set1.A1 - set1.A0); - set2.Volume = (set2.R1 - set2.R0) * (set2.G1 - set2.G0) * (set2.B1 - set2.B0) * (set2.A1 - set2.A0); + set1.Volume = (set1.RMax - set1.RMin) * (set1.GMax - set1.GMin) * (set1.BMax - set1.BMin) * (set1.AMax - set1.AMin); + set2.Volume = (set2.RMax - set2.RMin) * (set2.GMax - set2.GMin) * (set2.BMax - set2.BMin) * (set2.AMax - set2.AMin); return true; } @@ -798,13 +801,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { Span tagSpan = this.tag.GetSpan(); - for (int r = cube.R0 + 1; r <= cube.R1; r++) + for (int r = cube.RMin + 1; r <= cube.RMax; r++) { - for (int g = cube.G0 + 1; g <= cube.G1; g++) + for (int g = cube.GMin + 1; g <= cube.GMax; g++) { - for (int b = cube.B0 + 1; b <= cube.B1; b++) + for (int b = cube.BMin + 1; b <= cube.BMax; b++) { - for (int a = cube.A0 + 1; a <= cube.A1; a++) + for (int a = cube.AMin + 1; a <= cube.AMax; a++) { tagSpan[GetPaletteIndex(r, g, b, a)] = label; } @@ -819,12 +822,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization private void BuildCube() { this.colorCube = new Box[this.colors]; - float[] vv = new float[this.colors]; + double[] vv = new double[this.colors]; ref Box cube = ref this.colorCube[0]; - cube.R0 = cube.G0 = cube.B0 = cube.A0 = 0; - cube.R1 = cube.G1 = cube.B1 = IndexCount - 1; - cube.A1 = IndexAlphaCount - 1; + cube.RMin = cube.GMin = cube.BMin = cube.AMin = 0; + cube.RMax = cube.GMax = cube.BMax = IndexCount - 1; + cube.AMax = IndexAlphaCount - 1; int next = 0; @@ -839,13 +842,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } else { - vv[next] = 0F; + vv[next] = 0D; i--; } next = 0; - float temp = vv[0]; + double temp = vv[0]; for (int k = 1; k <= i; k++) { if (vv[k] > temp) @@ -855,7 +858,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } - if (temp <= 0F) + if (temp <= 0D) { this.colors = i + 1; break; @@ -897,52 +900,83 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Represents a box color cube. /// - private struct Box + private struct Box : IEquatable { /// /// Gets or sets the min red value, exclusive. /// - public int R0; + public int RMin; /// /// Gets or sets the max red value, inclusive. /// - public int R1; + public int RMax; /// /// Gets or sets the min green value, exclusive. /// - public int G0; + public int GMin; /// /// Gets or sets the max green value, inclusive. /// - public int G1; + public int GMax; /// /// Gets or sets the min blue value, exclusive. /// - public int B0; + public int BMin; /// /// Gets or sets the max blue value, inclusive. /// - public int B1; + public int BMax; /// /// Gets or sets the min alpha value, exclusive. /// - public int A0; + public int AMin; /// /// Gets or sets the max alpha value, inclusive. /// - public int A1; + public int AMax; /// /// Gets or sets the volume. /// public int Volume; + + /// + public override bool Equals(object obj) => obj is Box box && this.Equals(box); + + /// + public bool Equals(Box other) => + this.RMin == other.RMin + && this.RMax == other.RMax + && this.GMin == other.GMin + && this.GMax == other.GMax + && this.BMin == other.BMin + && this.BMax == other.BMax + && this.AMin == other.AMin + && this.AMax == other.AMax + && this.Volume == other.Volume; + + /// + public override int GetHashCode() + { + HashCode hash = default; + hash.Add(this.RMin); + hash.Add(this.RMax); + hash.Add(this.GMin); + hash.Add(this.GMax); + hash.Add(this.BMin); + hash.Add(this.BMax); + hash.Add(this.AMin); + hash.Add(this.AMax); + hash.Add(this.Volume); + return hash.ToHashCode(); + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs new file mode 100644 index 000000000..3eacd74ea --- /dev/null +++ b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs @@ -0,0 +1,168 @@ +using System; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Quantization; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Quantization +{ + public class WuQuantizerTests + { + [Fact] + public void SinglePixelOpaque() + { + Configuration config = Configuration.Default; + var quantizer = new WuQuantizer(false); + + using (var image = new Image(config, 1, 1, Rgba32.Black)) + using (QuantizedFrame result = quantizer.CreateFrameQuantizer(config).QuantizeFrame(image.Frames[0])) + { + Assert.Equal(1, result.Palette.Length); + Assert.Equal(1, result.GetPixelSpan().Length); + + Assert.Equal(Rgba32.Black, result.Palette[0]); + Assert.Equal(0, result.GetPixelSpan()[0]); + } + } + + [Fact] + public void SinglePixelTransparent() + { + Configuration config = Configuration.Default; + var quantizer = new WuQuantizer(false); + + using (var image = new Image(config, 1, 1, default(Rgba32))) + using (QuantizedFrame result = quantizer.CreateFrameQuantizer(config).QuantizeFrame(image.Frames[0])) + { + Assert.Equal(1, result.Palette.Length); + Assert.Equal(1, result.GetPixelSpan().Length); + + Assert.Equal(default, result.Palette[0]); + Assert.Equal(0, result.GetPixelSpan()[0]); + } + } + + [Fact] + public void GrayScale() => TestScale(c => new Rgba32(c, c, c, 128)); + + [Fact] + public void RedScale() => TestScale(c => new Rgba32(c, 0, 0, 128)); + + [Fact] + public void GreenScale() => TestScale(c => new Rgba32(0, c, 0, 128)); + + [Fact] + public void BlueScale() => TestScale(c => new Rgba32(0, 0, c, 128)); + + [Fact] + public void AlphaScale() => TestScale(c => new Rgba32(0, 0, 0, c)); + + [Fact] + public void Palette256() + { + using (var image = new Image(1, 256)) + { + for (int i = 0; i < 256; i++) + { + byte r = (byte)((i % 4) * 85); + byte g = (byte)(((i / 4) % 4) * 85); + byte b = (byte)(((i / 16) % 4) * 85); + byte a = (byte)((i / 64) * 85); + + image[0, i] = new Rgba32(r, g, b, a); + } + + Configuration config = Configuration.Default; + var quantizer = new WuQuantizer(false); + using (IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config)) + using (QuantizedFrame result = frameQuantizer.QuantizeFrame(image.Frames[0])) + { + Assert.Equal(256, result.Palette.Length); + Assert.Equal(256, result.GetPixelSpan().Length); + + var actualImage = new Image(1, 256); + + int paletteCount = result.Palette.Length - 1; + for (int y = 0; y < actualImage.Height; y++) + { + Span row = actualImage.GetPixelRowSpan(y); + ReadOnlySpan quantizedPixelSpan = result.GetPixelSpan(); + int yy = y * actualImage.Width; + + for (int x = 0; x < actualImage.Width; x++) + { + int i = x + yy; + row[x] = result.Palette[Math.Min(paletteCount, quantizedPixelSpan[i])]; + } + } + + Assert.True(image.GetPixelSpan().SequenceEqual(actualImage.GetPixelSpan())); + } + } + } + + [Theory] + [WithFile(TestImages.Png.LowColorVariance, PixelTypes.Rgba32)] + public void LowVariance(TestImageProvider provider) + where TPixel : struct, IPixel + { + // See https://github.com/SixLabors/ImageSharp/issues/866 + using (Image image = provider.GetImage()) + { + Configuration config = Configuration.Default; + var quantizer = new WuQuantizer(false); + using (IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config)) + using (QuantizedFrame result = frameQuantizer.QuantizeFrame(image.Frames[0])) + { + Assert.Equal(48, result.Palette.Length); + } + } + } + + private static void TestScale(Func pixelBuilder) + { + using (var image = new Image(1, 256)) + using (var expectedImage = new Image(1, 256)) + using (var actualImage = new Image(1, 256)) + { + for (int i = 0; i < 256; i++) + { + byte c = (byte)i; + image[0, i] = pixelBuilder.Invoke(c); + } + + for (int i = 0; i < 256; i++) + { + byte c = (byte)((i & ~7) + 4); + expectedImage[0, i] = pixelBuilder.Invoke(c); + } + + Configuration config = Configuration.Default; + var quantizer = new WuQuantizer(false); + + using (IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config)) + using (QuantizedFrame result = frameQuantizer.QuantizeFrame(image.Frames[0])) + { + Assert.Equal(4 * 8, result.Palette.Length); + Assert.Equal(256, result.GetPixelSpan().Length); + + int paletteCount = result.Palette.Length - 1; + for (int y = 0; y < actualImage.Height; y++) + { + Span row = actualImage.GetPixelRowSpan(y); + ReadOnlySpan quantizedPixelSpan = result.GetPixelSpan(); + int yy = y * actualImage.Width; + + for (int x = 0; x < actualImage.Width; x++) + { + int i = x + yy; + row[x] = result.Palette[Math.Min(paletteCount, quantizedPixelSpan[i])]; + } + } + } + + Assert.True(expectedImage.GetPixelSpan().SequenceEqual(actualImage.GetPixelSpan())); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 909969624..1efb9e35f 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -53,6 +53,7 @@ namespace SixLabors.ImageSharp.Tests public const string Gray2BitTrans = "Png/gray-2-tRNS.png"; public const string Gray4BitTrans = "Png/gray-4-tRNS.png"; public const string Gray8BitTrans = "Png/gray-8-tRNS.png"; + public const string LowColorVariance = "Png/low-variance.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html public const string Filter0 = "Png/filter0.png"; diff --git a/tests/Images/Input/Png/low-variance.png b/tests/Images/Input/Png/low-variance.png new file mode 100644 index 0000000000000000000000000000000000000000..5b6c19bace8ef66d02b0fec96e2f06b9f2534701 GIT binary patch literal 7844 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 Date: Sat, 13 Apr 2019 21:01:04 -0500 Subject: [PATCH 2/3] Nits - Benchmarks (#884) * Update metadata names * Use WithIterationCount * Format Benchmark documents * Update copyright assignment to Six Labors & Contributors * Update deps * React to Benchmark library update --- tests/ImageSharp.Benchmarks/BenchmarkBase.cs | 9 ++-- .../ImageSharp.Benchmarks/Codecs/DecodeBmp.cs | 2 +- .../Codecs/DecodeFilteredPng.cs | 4 +- .../ImageSharp.Benchmarks/Codecs/DecodePng.cs | 1 - .../Codecs/ImageBenchmarkTests.cs | 4 +- .../BlockOperations/Block8x8F_CopyTo2x2.cs | 40 +++++++++------ .../Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs | 8 +-- .../Codecs/Jpeg/EncodeJpeg.cs | 18 +++---- .../Codecs/MultiImageBenchmarkBase.cs | 18 +++---- .../Color/ColorEquality.cs | 12 ++--- .../Color/ColorspaceCieXyzToCieLabConvert.cs | 14 ++--- .../ColorspaceCieXyzToHunterLabConvert.cs | 15 +++--- .../Color/ColorspaceCieXyzToLmsConvert.cs | 15 +++--- .../Color/ColorspaceCieXyzToRgbConvert.cs | 14 ++--- .../ImageSharp.Benchmarks/Color/RgbToYCbCr.cs | 32 ++++++------ .../Color/RgbWorkingSpaceAdapt.cs | 15 +++--- tests/ImageSharp.Benchmarks/Config.cs | 17 +++---- .../Drawing/DrawBeziers.cs | 38 +++++++------- .../Drawing/DrawLines.cs | 51 +++++++++---------- .../Drawing/DrawPolygon.cs | 35 ++++++------- .../ImageSharp.Benchmarks/Drawing/DrawText.cs | 26 ++++------ .../Drawing/DrawTextOutline.cs | 32 +++++------- .../Drawing/FillPolygon.cs | 49 +++++++++--------- .../Drawing/FillRectangle.cs | 24 ++++----- .../Drawing/FillWithPattern.cs | 28 +++++----- .../ImageSharp.Benchmarks/General/Array2D.cs | 14 +++-- .../General/ArrayCopy.cs | 19 ++++--- .../General/ArrayReverse.cs | 14 +++-- .../General/BasicMath/ClampInt32IntoByte.cs | 4 +- .../PixelConversion_ConvertToRgba32.cs | 5 +- .../PixelConversion_ConvertToVector4.cs | 2 - .../General/Vector4Constants.cs | 10 ++-- .../General/Vectorization/BitwiseOrUint32.cs | 8 +-- .../General/Vectorization/DivFloat.cs | 12 ++--- .../General/Vectorization/DivUInt32.cs | 14 ++--- .../General/Vectorization/Divide.cs | 9 ++-- .../General/Vectorization/MulFloat.cs | 8 +-- .../General/Vectorization/MulUInt32.cs | 10 ++-- .../General/Vectorization/Multiply.cs | 6 +-- .../Vectorization/ReinterpretUInt32AsFloat.cs | 12 ++--- .../Vectorization/SIMDBenchmarkBase.cs | 11 ++-- .../ImageSharp.Benchmarks.csproj | 6 +-- tests/ImageSharp.Benchmarks/Program.cs | 13 ++--- tests/ImageSharp.Benchmarks/Samplers/Crop.cs | 42 +++++++-------- .../Samplers/DetectEdges.cs | 6 +-- tests/ImageSharp.Benchmarks/Samplers/Glow.cs | 13 +++-- .../ImageSharp.Benchmarks/Samplers/Resize.cs | 1 - .../ImageSharp.Benchmarks/Samplers/Rotate.cs | 5 +- tests/ImageSharp.Benchmarks/Samplers/Skew.cs | 5 +- 49 files changed, 352 insertions(+), 418 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/BenchmarkBase.cs b/tests/ImageSharp.Benchmarks/BenchmarkBase.cs index 6db03a448..87ed8fa42 100644 --- a/tests/ImageSharp.Benchmarks/BenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/BenchmarkBase.cs @@ -1,7 +1,8 @@ -namespace SixLabors.ImageSharp.Benchmarks -{ - using SixLabors.ImageSharp.Formats; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +namespace SixLabors.ImageSharp.Benchmarks +{ /// /// The image benchmark base class. /// @@ -15,4 +16,4 @@ // Add Image Formats } } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs index 30799aabf..1ab5ed309 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs @@ -54,4 +54,4 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs } } } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs index ff378c75c..cc946e05a 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// using System.IO; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs index 39f09b6b6..a19d8fa91 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs @@ -11,7 +11,6 @@ using SDImage = System.Drawing.Image; namespace SixLabors.ImageSharp.Benchmarks.Codecs { - [Config(typeof(Config.ShortClr))] public class DecodePng : BenchmarkBase { diff --git a/tests/ImageSharp.Benchmarks/Codecs/ImageBenchmarkTests.cs b/tests/ImageSharp.Benchmarks/Codecs/ImageBenchmarkTests.cs index ee77a2b6b..7c3da90db 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/ImageBenchmarkTests.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/ImageBenchmarkTests.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// // This file contains small, cheap and "unit test" benchmarks to test MultiImageBenchmarkBase. // Need this because there are no real test cases for the common benchmark utility stuff. diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs index 65176af5b..3d9b54dff 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs @@ -364,22 +364,30 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations ref Vector4 dTopLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset)); ref Vector4 dBottomLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset + destStride)); - var xyLeft = new Vector4(sLeft.X); - xyLeft.Z = sLeft.Y; - xyLeft.W = sLeft.Y; - - var zwLeft = new Vector4(sLeft.Z); - zwLeft.Z = sLeft.W; - zwLeft.W = sLeft.W; - - var xyRight = new Vector4(sRight.X); - xyRight.Z = sRight.Y; - xyRight.W = sRight.Y; - - var zwRight = new Vector4(sRight.Z); - zwRight.Z = sRight.W; - zwRight.W = sRight.W; - + var xyLeft = new Vector4(sLeft.X) + { + Z = sLeft.Y, + W = sLeft.Y + }; + + var zwLeft = new Vector4(sLeft.Z) + { + Z = sLeft.W, + W = sLeft.W + }; + + var xyRight = new Vector4(sRight.X) + { + Z = sRight.Y, + W = sRight.Y + }; + + var zwRight = new Vector4(sRight.Z) + { + Z = sRight.W, + W = sRight.W + }; + dTopLeft = xyLeft; Unsafe.Add(ref dTopLeft, 1) = zwLeft; Unsafe.Add(ref dTopLeft, 2) = xyRight; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs index fe112042e..8247ba42b 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -5,6 +5,7 @@ using System.Drawing; using System.IO; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Diagnosers; using BenchmarkDotNet.Jobs; using SixLabors.ImageSharp.Formats.Jpeg; @@ -26,8 +27,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { public Config() { - // Uncomment if you want to use any of the diagnoser - this.Add(new BenchmarkDotNet.Diagnosers.MemoryDiagnoser()); + this.Add(MemoryDiagnoser.Default); } public class ShortClr : Benchmarks.Config @@ -35,8 +35,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg public ShortClr() { this.Add( - //Job.Clr.WithLaunchCount(1).WithWarmupCount(2).WithTargetCount(3), - Job.Core.WithLaunchCount(1).WithWarmupCount(2).WithTargetCount(3) + //Job.Clr.WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3), + Job.Core.WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3) ); } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs index d934a1d6d..c617d25c0 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs @@ -1,18 +1,16 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// using SixLabors.ImageSharp.PixelFormats; +using BenchmarkDotNet.Attributes; + namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg { using System.Drawing; using System.Drawing.Imaging; using System.IO; - using BenchmarkDotNet.Attributes; - using CoreImage = SixLabors.ImageSharp.Image; public class EncodeJpeg : BenchmarkBase @@ -45,19 +43,19 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg [Benchmark(Baseline = true, Description = "System.Drawing Jpeg")] public void JpegSystemDrawing() { - using (var memoryStream = new MemoryStream()) + using (var stream = new MemoryStream()) { - this.bmpDrawing.Save(memoryStream, ImageFormat.Jpeg); + this.bmpDrawing.Save(stream, ImageFormat.Jpeg); } } [Benchmark(Description = "ImageSharp Jpeg")] public void JpegCore() { - using (var memoryStream = new MemoryStream()) + using (var stream = new MemoryStream()) { - this.bmpCore.SaveAsJpeg(memoryStream); + this.bmpCore.SaveAsJpeg(stream); } } } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs index 446c03859..75bbf21a3 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// using BenchmarkDotNet.Configs; using BenchmarkDotNet.Jobs; @@ -18,7 +16,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs using System.Numerics; using BenchmarkDotNet.Attributes; - + using BenchmarkDotNet.Diagnosers; using SixLabors.ImageSharp.Tests; using CoreImage = ImageSharp.Image; @@ -30,7 +28,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs public Config() { // Uncomment if you want to use any of the diagnoser - this.Add(new BenchmarkDotNet.Diagnosers.MemoryDiagnoser()); + this.Add(MemoryDiagnoser.Default); } public class ShortClr : Benchmarks.Config @@ -38,7 +36,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs public ShortClr() { this.Add( - Job.Core.WithLaunchCount(1).WithWarmupCount(1).WithTargetCount(2) + Job.Core.WithLaunchCount(1).WithWarmupCount(1).WithIterationCount(2) ); } } @@ -47,7 +45,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs protected Dictionary FileNamesToBytes = new Dictionary(); protected Dictionary> FileNamesToImageSharpImages = new Dictionary>(); - protected Dictionary FileNamesToSystemDrawingImages = new Dictionary(); + protected Dictionary FileNamesToSystemDrawingImages = new Dictionary(); /// /// The values of this enum separate input files into categories @@ -152,7 +150,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs { foreach (KeyValuePair kv in this.FileNames2Bytes) { - using (MemoryStream memoryStream = new MemoryStream(kv.Value)) + using (var memoryStream = new MemoryStream(kv.Value)) { try { @@ -179,7 +177,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs byte[] bytes = kv.Value; string fn = kv.Key; - using (MemoryStream ms1 = new MemoryStream(bytes)) + using (var ms1 = new MemoryStream(bytes)) { this.FileNamesToImageSharpImages[fn] = CoreImage.Load(ms1); @@ -223,7 +221,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs protected void ForEachImageSharpImage(Func, MemoryStream, object> operation) { - using (MemoryStream workStream = new MemoryStream()) + using (var workStream = new MemoryStream()) { this.ForEachImageSharpImage( diff --git a/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs b/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs index 02017cbb7..602e1137f 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorEquality.cs @@ -1,14 +1,12 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// -namespace SixLabors.ImageSharp.Benchmarks -{ - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; - using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.PixelFormats; +namespace SixLabors.ImageSharp.Benchmarks +{ using SystemColor = System.Drawing.Color; public class ColorEquality diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs index cc3472e22..855f5b9b4 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs @@ -1,13 +1,13 @@ -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces -{ - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; - using Colourful; - using Colourful.Conversion; +using Colourful; +using Colourful.Conversion; - using SixLabors.ImageSharp.ColorSpaces; - using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces +{ public class ColorspaceCieXyzToCieLabConvert { private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F); diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs index d10999518..07870b3a8 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs @@ -1,13 +1,13 @@ -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces -{ - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; - using Colourful; - using Colourful.Conversion; +using Colourful; +using Colourful.Conversion; - using SixLabors.ImageSharp.ColorSpaces; - using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces +{ public class ColorspaceCieXyzToHunterLabConvert { private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F); @@ -18,7 +18,6 @@ private static readonly ColourfulConverter ColourfulConverter = new ColourfulConverter(); - [Benchmark(Baseline = true, Description = "Colourful Convert")] public double ColourfulConvert() { diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs index da7b9c3dd..4d9ba8928 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs @@ -1,13 +1,13 @@ -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces -{ - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; - using Colourful; - using Colourful.Conversion; +using Colourful; +using Colourful.Conversion; - using SixLabors.ImageSharp.ColorSpaces; - using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces +{ public class ColorspaceCieXyzToLmsConvert { private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F); @@ -18,7 +18,6 @@ private static readonly ColourfulConverter ColourfulConverter = new ColourfulConverter(); - [Benchmark(Baseline = true, Description = "Colourful Convert")] public double ColourfulConvert() { diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs index 2a5754ab0..f20ffdcab 100644 --- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs +++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs @@ -1,13 +1,13 @@ -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces -{ - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; - using Colourful; - using Colourful.Conversion; +using Colourful; +using Colourful.Conversion; - using SixLabors.ImageSharp.ColorSpaces; - using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces +{ public class ColorspaceCieXyzToRgbConvert { private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F); diff --git a/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs b/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs index 07ae17d75..b4e5ab380 100644 --- a/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs +++ b/tests/ImageSharp.Benchmarks/Color/RgbToYCbCr.cs @@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.Benchmarks OnStackInputCache.Byte input = OnStackInputCache.Byte.Create(this.inputSourceRGB); // On-stack output: - Result result = default(Result); + Result result = default; float* yPtr = (float*)&result.Y; float* cbPtr = (float*)&result.Cb; float* crPtr = (float*)&result.Cr; @@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.Benchmarks OnStackInputCache.Byte input = OnStackInputCache.Byte.Create(this.inputSourceRGB); // On-stack output: - Result result = default(Result); + Result result = default; float* yPtr = (float*)&result.Y; float* cbPtr = (float*)&result.Cb; float* crPtr = (float*)&result.Cr; @@ -194,15 +194,15 @@ namespace SixLabors.ImageSharp.Benchmarks // Copy the input to the stack: // On-stack output: - Result result = default(Result); + Result result = default; float* yPtr = (float*)&result.Y; float* cbPtr = (float*)&result.Cb; float* crPtr = (float*)&result.Cr; // end of code-bloat block :) - Vector yCoeffs = new Vector(ScaledCoeffs.Y); - Vector cbCoeffs = new Vector(ScaledCoeffs.Cb); - Vector crCoeffs = new Vector(ScaledCoeffs.Cr); + var yCoeffs = new Vector(ScaledCoeffs.Y); + var cbCoeffs = new Vector(ScaledCoeffs.Cb); + var crCoeffs = new Vector(ScaledCoeffs.Cr); for (int i = 0; i < this.inputSourceRGB.Length; i++) { @@ -240,23 +240,23 @@ namespace SixLabors.ImageSharp.Benchmarks // Copy the input to the stack: // On-stack output: - Result result = default(Result); + Result result = default; float* yPtr = (float*)&result.Y; float* cbPtr = (float*)&result.Cb; float* crPtr = (float*)&result.Cr; // end of code-bloat block :) - Vector yCoeffs = new Vector(ScaledCoeffs.Y); - Vector cbCoeffs = new Vector(ScaledCoeffs.Cb); - Vector crCoeffs = new Vector(ScaledCoeffs.Cr); + var yCoeffs = new Vector(ScaledCoeffs.Y); + var cbCoeffs = new Vector(ScaledCoeffs.Cb); + var crCoeffs = new Vector(ScaledCoeffs.Cr); - Vector leftY = new Vector(ScaledCoeffs.SelectLeft.Y); - Vector leftCb = new Vector(ScaledCoeffs.SelectLeft.Cb); - Vector leftCr = new Vector(ScaledCoeffs.SelectLeft.Cr); + var leftY = new Vector(ScaledCoeffs.SelectLeft.Y); + var leftCb = new Vector(ScaledCoeffs.SelectLeft.Cb); + var leftCr = new Vector(ScaledCoeffs.SelectLeft.Cr); - Vector rightY = new Vector(ScaledCoeffs.SelectRight.Y); - Vector rightCb = new Vector(ScaledCoeffs.SelectRight.Cb); - Vector rightCr = new Vector(ScaledCoeffs.SelectRight.Cr); + var rightY = new Vector(ScaledCoeffs.SelectRight.Y); + var rightCb = new Vector(ScaledCoeffs.SelectRight.Cb); + var rightCr = new Vector(ScaledCoeffs.SelectRight.Cr); for (int i = 0; i < this.inputSourceRGB.Length; i++) { diff --git a/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs b/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs index 92008f6e2..060a28550 100644 --- a/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs +++ b/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs @@ -1,13 +1,13 @@ -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces -{ - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; - using Colourful; - using Colourful.Conversion; +using Colourful; +using Colourful.Conversion; - using SixLabors.ImageSharp.ColorSpaces; - using SixLabors.ImageSharp.ColorSpaces.Conversion; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces +{ public class RgbWorkingSpaceAdapt { private static readonly Rgb Rgb = new Rgb(0.206162F, 0.260277F, 0.746717F, RgbWorkingSpaces.WideGamutRgb); @@ -18,7 +18,6 @@ private static readonly ColourfulConverter ColourfulConverter = new ColourfulConverter { TargetRGBWorkingSpace = RGBWorkingSpaces.sRGB }; - [Benchmark(Baseline = true, Description = "Colourful Adapt")] public RGBColor ColourfulConvert() { diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs index b46757942..0543cbc50 100644 --- a/tests/ImageSharp.Benchmarks/Config.cs +++ b/tests/ImageSharp.Benchmarks/Config.cs @@ -1,20 +1,17 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Diagnosers; +using BenchmarkDotNet.Jobs; namespace SixLabors.ImageSharp.Benchmarks { - using BenchmarkDotNet.Jobs; - public class Config : ManualConfig { public Config() { - // Uncomment if you want to use any of the diagnoser - this.Add(new BenchmarkDotNet.Diagnosers.MemoryDiagnoser()); + this.Add(MemoryDiagnoser.Default); } public class ShortClr : Config @@ -22,9 +19,9 @@ namespace SixLabors.ImageSharp.Benchmarks public ShortClr() { this.Add( - Job.Clr.WithLaunchCount(1).WithWarmupCount(3).WithTargetCount(3), - Job.Core.WithLaunchCount(1).WithWarmupCount(3).WithTargetCount(3) - ); + Job.Clr.WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3), + Job.Core.WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3) + ); } } } diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs index 34dd9d4dc..bc9c1c96d 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// using System.Drawing; using System.Drawing.Drawing2D; @@ -19,27 +17,25 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Baseline = true, Description = "System.Drawing Draw Beziers")] public void DrawPathSystemDrawing() { - using (Bitmap destination = new Bitmap(800, 800)) + using (var destination = new Bitmap(800, 800)) + using (var graphics = Graphics.FromImage(destination)) { + graphics.InterpolationMode = InterpolationMode.Default; + graphics.SmoothingMode = SmoothingMode.AntiAlias; - using (Graphics graphics = Graphics.FromImage(destination)) + using (var pen = new Pen(Color.HotPink, 10)) { - graphics.InterpolationMode = InterpolationMode.Default; - graphics.SmoothingMode = SmoothingMode.AntiAlias; - using (var pen = new Pen(System.Drawing.Color.HotPink, 10)) - { - graphics.DrawBeziers(pen, new[] { - new PointF(10, 500), - new PointF(30, 10), - new PointF(240, 30), - new PointF(300, 500) - }); - } + graphics.DrawBeziers(pen, new[] { + new PointF(10, 500), + new PointF(30, 10), + new PointF(240, 30), + new PointF(300, 500) + }); } - using (MemoryStream ms = new MemoryStream()) + using (var stream = new MemoryStream()) { - destination.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp); + destination.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp); } } } @@ -47,7 +43,7 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Description = "ImageSharp Draw Beziers")] public void DrawLinesCore() { - using (Image image = new Image(800, 800)) + using (var image = new Image(800, 800)) { image.Mutate(x => x.DrawBeziers( Rgba32.HotPink, @@ -59,9 +55,9 @@ namespace SixLabors.ImageSharp.Benchmarks new Vector2(300, 500) })); - using (MemoryStream ms = new MemoryStream()) + using (var stream = new MemoryStream()) { - image.SaveAsBmp(ms); + image.SaveAsBmp(stream); } } } diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs index 091f36762..4265525e5 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs @@ -1,44 +1,41 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// -namespace SixLabors.ImageSharp.Benchmarks -{ - using System.Drawing; - using System.Drawing.Drawing2D; - using System.IO; - using System.Numerics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.IO; +using System.Numerics; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; - using SixLabors.ImageSharp.PixelFormats; - using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +namespace SixLabors.ImageSharp.Benchmarks +{ public class DrawLines : BenchmarkBase { [Benchmark(Baseline = true, Description = "System.Drawing Draw Lines")] public void DrawPathSystemDrawing() { using (var destination = new Bitmap(800, 800)) + using (var graphics = Graphics.FromImage(destination)) { - using (var graphics = Graphics.FromImage(destination)) + graphics.InterpolationMode = InterpolationMode.Default; + graphics.SmoothingMode = SmoothingMode.AntiAlias; + + using (var pen = new Pen(Color.HotPink, 10)) { - graphics.InterpolationMode = InterpolationMode.Default; - graphics.SmoothingMode = SmoothingMode.AntiAlias; - using (var pen = new Pen(System.Drawing.Color.HotPink, 10)) - { - graphics.DrawLines(pen, new[] { - new PointF(10, 10), - new PointF(550, 50), - new PointF(200, 400) - }); - } + graphics.DrawLines(pen, new[] { + new PointF(10, 10), + new PointF(550, 50), + new PointF(200, 400) + }); } - using (var ms = new MemoryStream()) + using (var stream = new MemoryStream()) { - destination.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp); + destination.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp); } } } @@ -57,9 +54,9 @@ namespace SixLabors.ImageSharp.Benchmarks new Vector2(200, 400) })); - using (var ms = new MemoryStream()) + using (var stream = new MemoryStream()) { - image.SaveAsBmp(ms); + image.SaveAsBmp(stream); } } } diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs index ab8a7134e..4172b3c38 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// using System.Drawing; using System.Drawing.Drawing2D; @@ -19,26 +17,23 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Baseline = true, Description = "System.Drawing Draw Polygon")] public void DrawPolygonSystemDrawing() { - using (Bitmap destination = new Bitmap(800, 800)) + using (var destination = new Bitmap(800, 800)) + using (var graphics = Graphics.FromImage(destination)) { - - using (Graphics graphics = Graphics.FromImage(destination)) + graphics.InterpolationMode = InterpolationMode.Default; + graphics.SmoothingMode = SmoothingMode.AntiAlias; + using (var pen = new Pen(Color.HotPink, 10)) { - graphics.InterpolationMode = InterpolationMode.Default; - graphics.SmoothingMode = SmoothingMode.AntiAlias; - using (var pen = new Pen(System.Drawing.Color.HotPink, 10)) - { - graphics.DrawPolygon(pen, new[] { - new PointF(10, 10), - new PointF(550, 50), - new PointF(200, 400) - }); - } + graphics.DrawPolygon(pen, new[] { + new PointF(10, 10), + new PointF(550, 50), + new PointF(200, 400) + }); } - using (MemoryStream ms = new MemoryStream()) + using (var stream = new MemoryStream()) { - destination.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp); + destination.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp); } } } @@ -46,7 +41,7 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Description = "ImageSharp Draw Polygon")] public void DrawPolygonCore() { - using (Image image = new Image(800, 800)) + using (var image = new Image(800, 800)) { image.Mutate(x => x.DrawPolygon( Rgba32.HotPink, @@ -57,7 +52,7 @@ namespace SixLabors.ImageSharp.Benchmarks new Vector2(200, 400) })); - using (MemoryStream ms = new MemoryStream()) + using (var ms = new MemoryStream()) { image.SaveAsBmp(ms); } diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawText.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawText.cs index 60c58dadc..8c840d8c3 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawText.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawText.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// using System.Drawing; using System.Drawing.Drawing2D; @@ -14,11 +12,9 @@ using SixLabors.ImageSharp.Processing.Processors.Text; namespace SixLabors.ImageSharp.Benchmarks { - [MemoryDiagnoser] public class DrawText : BenchmarkBase { - [Params(10, 100)] public int TextIterations { get; set; } public string TextPhrase { get; set; } = "Hello World"; @@ -28,26 +24,22 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Baseline = true, Description = "System.Drawing Draw Text")] public void DrawTextSystemDrawing() { - using (Bitmap destination = new Bitmap(800, 800)) + using (var destination = new Bitmap(800, 800)) + using (var graphics = Graphics.FromImage(destination)) { - - using (Graphics graphics = Graphics.FromImage(destination)) + graphics.InterpolationMode = InterpolationMode.Default; + graphics.SmoothingMode = SmoothingMode.AntiAlias; + using (var font = new Font("Arial", 12, GraphicsUnit.Point)) { - graphics.InterpolationMode = InterpolationMode.Default; - graphics.SmoothingMode = SmoothingMode.AntiAlias; - using (var font = new Font("Arial", 12, GraphicsUnit.Point)) - { - graphics.DrawString(TextToRender, font, System.Drawing.Brushes.HotPink, new RectangleF(10, 10, 780, 780)); - } + graphics.DrawString(TextToRender, font, System.Drawing.Brushes.HotPink, new RectangleF(10, 10, 780, 780)); } } } - [Benchmark(Description = "ImageSharp Draw Text - Cached Glyphs")] public void DrawTextCore() { - using (Image image = new Image(800, 800)) + using (var image = new Image(800, 800)) { var font = SixLabors.Fonts.SystemFonts.CreateFont("Arial", 12); image.Mutate(x => x.ApplyProcessor(new DrawTextProcessor(new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, Processing.Brushes.Solid(Rgba32.HotPink), null, new SixLabors.Primitives.PointF(10, 10)))); @@ -57,7 +49,7 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Description = "ImageSharp Draw Text - Nieve")] public void DrawTextCoreOld() { - using (Image image = new Image(800, 800)) + using (var image = new Image(800, 800)) { var font = SixLabors.Fonts.SystemFonts.CreateFont("Arial", 12); image.Mutate(x => DrawTextOldVersion(x, new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, Processing.Brushes.Solid(Rgba32.HotPink), null, new SixLabors.Primitives.PointF(10, 10))); diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs index 2d6505a91..b99c47960 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// using System.Drawing; using System.Drawing.Drawing2D; @@ -13,34 +11,28 @@ using SixLabors.ImageSharp.Processing.Processors.Text; namespace SixLabors.ImageSharp.Benchmarks { - [MemoryDiagnoser] public class DrawTextOutline : BenchmarkBase { - [Params(10, 100)] public int TextIterations { get; set; } public string TextPhrase { get; set; } = "Hello World"; public string TextToRender => string.Join(" ", Enumerable.Repeat(TextPhrase, TextIterations)); - [Benchmark(Baseline = true, Description = "System.Drawing Draw Text Outline")] public void DrawTextSystemDrawing() { - using (Bitmap destination = new Bitmap(800, 800)) + using (var destination = new Bitmap(800, 800)) + using (var graphics = Graphics.FromImage(destination)) { - - using (Graphics graphics = Graphics.FromImage(destination)) + graphics.InterpolationMode = InterpolationMode.Default; + graphics.SmoothingMode = SmoothingMode.AntiAlias; + using (var pen = new Pen(Color.HotPink, 10)) + using (var font = new Font("Arial", 12, GraphicsUnit.Point)) + using (var gp = new GraphicsPath()) { - graphics.InterpolationMode = InterpolationMode.Default; - graphics.SmoothingMode = SmoothingMode.AntiAlias; - using (var pen = new Pen(System.Drawing.Color.HotPink, 10)) - using (var font = new Font("Arial", 12, GraphicsUnit.Point)) - using (var gp = new GraphicsPath()) - { - gp.AddString(TextToRender, font.FontFamily, (int)font.Style, font.Size, new RectangleF(10, 10, 780, 780), new StringFormat()); - graphics.DrawPath(pen, gp); - } + gp.AddString(TextToRender, font.FontFamily, (int)font.Style, font.Size, new RectangleF(10, 10, 780, 780), new StringFormat()); + graphics.DrawPath(pen, gp); } } } @@ -48,7 +40,7 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Description = "ImageSharp Draw Text Outline - Cached Glyphs")] public void DrawTextCore() { - using (Image image = new Image(800, 800)) + using (var image = new Image(800, 800)) { var font = SixLabors.Fonts.SystemFonts.CreateFont("Arial", 12); image.Mutate(x => x.ApplyProcessor(new DrawTextProcessor(new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, null, Processing.Pens.Solid(Rgba32.HotPink, 10), new SixLabors.Primitives.PointF(10, 10)))); @@ -58,7 +50,7 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Description = "ImageSharp Draw Text Outline - Nieve")] public void DrawTextCoreOld() { - using (Image image = new Image(800, 800)) + using (var image = new Image(800, 800)) { var font = SixLabors.Fonts.SystemFonts.CreateFont("Arial", 12); image.Mutate(x => DrawTextOldVersion(x, new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, null, Processing.Pens.Solid(Rgba32.HotPink, 10), new SixLabors.Primitives.PointF(10, 10))); diff --git a/tests/ImageSharp.Benchmarks/Drawing/FillPolygon.cs b/tests/ImageSharp.Benchmarks/Drawing/FillPolygon.cs index 8aadb85bf..396cc18d1 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/FillPolygon.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/FillPolygon.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// using System.Drawing; using System.Drawing.Drawing2D; @@ -21,31 +19,30 @@ namespace SixLabors.ImageSharp.Benchmarks public FillPolygon() { - this.shape = new Polygon(new LinearLineSegment(new Vector2(10, 10), - new Vector2(550, 50), - new Vector2(200, 400))); + this.shape = new Polygon(new LinearLineSegment( + new Vector2(10, 10), + new Vector2(550, 50), + new Vector2(200, 400))); } [Benchmark(Baseline = true, Description = "System.Drawing Fill Polygon")] public void DrawSolidPolygonSystemDrawing() { - using (Bitmap destination = new Bitmap(800, 800)) + using (var destination = new Bitmap(800, 800)) + + using (var graphics = Graphics.FromImage(destination)) { + graphics.SmoothingMode = SmoothingMode.AntiAlias; + graphics.FillPolygon(System.Drawing.Brushes.HotPink, + new[] { + new Point(10, 10), + new Point(550, 50), + new Point(200, 400) + }); - using (Graphics graphics = Graphics.FromImage(destination)) - { - graphics.SmoothingMode = SmoothingMode.AntiAlias; - graphics.FillPolygon(System.Drawing.Brushes.HotPink, - new[] - { - new Point(10, 10), - new Point(550, 50), - new Point(200, 400) - }); - } - using (MemoryStream ms = new MemoryStream()) + using (var stream = new MemoryStream()) { - destination.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp); + destination.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp); } } } @@ -53,7 +50,7 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Description = "ImageSharp Fill Polygon")] public void DrawSolidPolygonCore() { - using (Image image = new Image(800, 800)) + using (var image = new Image(800, 800)) { image.Mutate(x => x.FillPolygon( Rgba32.HotPink, @@ -63,9 +60,9 @@ namespace SixLabors.ImageSharp.Benchmarks new Vector2(200, 400) })); - using (MemoryStream ms = new MemoryStream()) + using (var stream = new MemoryStream()) { - image.SaveAsBmp(ms); + image.SaveAsBmp(stream); } } } @@ -73,15 +70,15 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Description = "ImageSharp Fill Polygon - cached shape")] public void DrawSolidPolygonCoreCahced() { - using (Image image = new Image(800, 800)) + using (var image = new Image(800, 800)) { image.Mutate(x => x.Fill( Rgba32.HotPink, this.shape)); - using (MemoryStream ms = new MemoryStream()) + using (var stream = new MemoryStream()) { - image.SaveAsBmp(ms); + image.SaveAsBmp(stream); } } } diff --git a/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs b/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs index 643e4ac9a..d45b791ae 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/FillRectangle.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// using System.Drawing; using System.Drawing.Drawing2D; @@ -15,22 +13,18 @@ using CoreSize = SixLabors.Primitives.Size; namespace SixLabors.ImageSharp.Benchmarks { - - public class FillRectangle : BenchmarkBase { [Benchmark(Baseline = true, Description = "System.Drawing Fill Rectangle")] public Size FillRectangleSystemDrawing() { - using (Bitmap destination = new Bitmap(800, 800)) + using (var destination = new Bitmap(800, 800)) + using (var graphics = Graphics.FromImage(destination)) { - - using (Graphics graphics = Graphics.FromImage(destination)) - { - graphics.InterpolationMode = InterpolationMode.Default; - graphics.SmoothingMode = SmoothingMode.AntiAlias; - graphics.FillRectangle(System.Drawing.Brushes.HotPink, new Rectangle(10, 10, 190, 140)); - } + graphics.InterpolationMode = InterpolationMode.Default; + graphics.SmoothingMode = SmoothingMode.AntiAlias; + graphics.FillRectangle(System.Drawing.Brushes.HotPink, new Rectangle(10, 10, 190, 140)); + return destination.Size; } } @@ -38,7 +32,7 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Description = "ImageSharp Fill Rectangle")] public CoreSize FillRactangleCore() { - using (Image image = new Image(800, 800)) + using (var image = new Image(800, 800)) { image.Mutate(x => x.Fill(Rgba32.HotPink, new CoreRectangle(10, 10, 190, 140))); @@ -49,7 +43,7 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Description = "ImageSharp Fill Rectangle - As Polygon")] public CoreSize FillPolygonCore() { - using (Image image = new Image(800, 800)) + using (var image = new Image(800, 800)) { image.Mutate(x => x.FillPolygon( Rgba32.HotPink, diff --git a/tests/ImageSharp.Benchmarks/Drawing/FillWithPattern.cs b/tests/ImageSharp.Benchmarks/Drawing/FillWithPattern.cs index 372361988..3c9cfd7e3 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/FillWithPattern.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/FillWithPattern.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// using System.Drawing; using System.Drawing.Drawing2D; @@ -21,19 +19,19 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Baseline = true, Description = "System.Drawing Fill with Pattern")] public void DrawPatternPolygonSystemDrawing() { - using (Bitmap destination = new Bitmap(800, 800)) + using (var destination = new Bitmap(800, 800)) + using (var graphics = Graphics.FromImage(destination)) { - using (Graphics graphics = Graphics.FromImage(destination)) + graphics.SmoothingMode = SmoothingMode.AntiAlias; + + using (var brush = new HatchBrush(HatchStyle.BackwardDiagonal, Color.HotPink)) { - graphics.SmoothingMode = SmoothingMode.AntiAlias; - using (var brush = new HatchBrush(HatchStyle.BackwardDiagonal, Color.HotPink)) - { - graphics.FillRectangle(brush, new Rectangle(0, 0, 800, 800)); // can't find a way to flood fill with a brush - } + graphics.FillRectangle(brush, new Rectangle(0, 0, 800, 800)); // can't find a way to flood fill with a brush } - using (MemoryStream ms = new MemoryStream()) + + using (var stream = new MemoryStream()) { - destination.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp); + destination.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp); } } } @@ -41,13 +39,13 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Description = "ImageSharp Fill with Pattern")] public void DrawPatternPolygon3Core() { - using (Image image = new Image(800, 800)) + using (var image = new Image(800, 800)) { image.Mutate(x => x.Fill(CoreBrushes.BackwardDiagonal(Rgba32.HotPink))); - using (MemoryStream ms = new MemoryStream()) + using (var stream = new MemoryStream()) { - image.SaveAsBmp(ms); + image.SaveAsBmp(stream); } } } diff --git a/tests/ImageSharp.Benchmarks/General/Array2D.cs b/tests/ImageSharp.Benchmarks/General/Array2D.cs index 60d89847f..1f8961fcd 100644 --- a/tests/ImageSharp.Benchmarks/General/Array2D.cs +++ b/tests/ImageSharp.Benchmarks/General/Array2D.cs @@ -1,16 +1,14 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System; +using System; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; - using SixLabors.ImageSharp.Primitives; +using SixLabors.ImageSharp.Primitives; +namespace SixLabors.ImageSharp.Benchmarks.General +{ /** * Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | -------------------------------------------- |------ |---------:|---------:|---------:|-------:|---------:| diff --git a/tests/ImageSharp.Benchmarks/General/ArrayCopy.cs b/tests/ImageSharp.Benchmarks/General/ArrayCopy.cs index ac6b3f93c..41c9ab6c7 100644 --- a/tests/ImageSharp.Benchmarks/General/ArrayCopy.cs +++ b/tests/ImageSharp.Benchmarks/General/ArrayCopy.cs @@ -1,15 +1,14 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - using BenchmarkDotNet.Attributes; - +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; + +namespace SixLabors.ImageSharp.Benchmarks.General +{ [Config(typeof(Config.ShortClr))] public class ArrayCopy { diff --git a/tests/ImageSharp.Benchmarks/General/ArrayReverse.cs b/tests/ImageSharp.Benchmarks/General/ArrayReverse.cs index 45a8519a9..c49c383eb 100644 --- a/tests/ImageSharp.Benchmarks/General/ArrayReverse.cs +++ b/tests/ImageSharp.Benchmarks/General/ArrayReverse.cs @@ -1,14 +1,12 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System; +using System; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace SixLabors.ImageSharp.Benchmarks.General +{ public class ArrayReverse { [Params(4, 16, 32)] @@ -58,4 +56,4 @@ namespace SixLabors.ImageSharp.Benchmarks.General } } } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs index 6ce82ba11..a8686fc18 100644 --- a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// using System; using System.Runtime.CompilerServices; diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs index d205e1e63..ea8b34c24 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs @@ -1,7 +1,4 @@ -// ReSharper disable InconsistentNaming - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; using BenchmarkDotNet.Attributes; diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs index 2bc3ee971..68a16b791 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs @@ -3,8 +3,6 @@ using System.Runtime.CompilerServices; using BenchmarkDotNet.Attributes; -using SixLabors.ImageSharp.PixelFormats; - namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion { public class PixelConversion_ConvertToVector4 diff --git a/tests/ImageSharp.Benchmarks/General/Vector4Constants.cs b/tests/ImageSharp.Benchmarks/General/Vector4Constants.cs index ae11806f3..3597207ee 100644 --- a/tests/ImageSharp.Benchmarks/General/Vector4Constants.cs +++ b/tests/ImageSharp.Benchmarks/General/Vector4Constants.cs @@ -1,10 +1,10 @@ -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System; - using System.Numerics; +using System; +using System.Numerics; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace SixLabors.ImageSharp.Benchmarks.General +{ /// /// Has it any effect on performance to store SIMD constants as static readonly fields? Is it OK to always inline them? /// Spoiler: the difference seems to be statistically insignificant! diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs index d189411b5..3afb796a7 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs @@ -1,9 +1,9 @@ -namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization -{ - using System.Numerics; +using System.Numerics; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization +{ public class BitwiseOrUInt32 { private uint[] input; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs index 637846747..be9534f7d 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs @@ -1,9 +1,9 @@ -namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization -{ - using System.Numerics; +using System.Numerics; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization +{ public class DivFloat { private float[] input; @@ -41,11 +41,11 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization [Benchmark] public void Simd() { - Vector v = new Vector(this.testValue); + var v = new Vector(this.testValue); for (int i = 0; i < this.input.Length; i += Vector.Count) { - Vector a = new Vector(this.input, i); + var a = new Vector(this.input, i); a = a / v; a.CopyTo(this.result, i); } diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs index 49ada2f36..bfc8d3de3 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs @@ -1,9 +1,9 @@ -namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization -{ - using System.Numerics; +using System.Numerics; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization +{ public class DivUInt32 { private uint[] input; @@ -32,6 +32,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization public void Standard() { uint v = this.testValue; + for (int i = 0; i < this.input.Length; i++) { this.result[i] = this.input[i] / v; @@ -41,11 +42,12 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization [Benchmark] public void Simd() { - Vector v = new Vector(this.testValue); + var v = new Vector(this.testValue); for (int i = 0; i < this.input.Length; i += Vector.Count) { - Vector a = new Vector(this.input, i); + var a = new Vector(this.input, i); + a = a / v; a.CopyTo(this.result, i); } diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs index b38429557..df09aa569 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs @@ -1,10 +1,9 @@ -namespace ImageSharp.Benchmarks.General.Vectorization -{ - using System; - using System.Numerics; +using System.Numerics; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace ImageSharp.Benchmarks.General.Vectorization +{ public class DivFloat : SIMDBenchmarkBase.Divide { protected override float GetTestValue() => 42; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs index 8c5f56818..418209cbc 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs @@ -1,9 +1,9 @@ -namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization -{ - using System.Numerics; +using System.Numerics; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization +{ public class MulFloat { private float[] input; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs index 913d4ce3c..7253dbd6a 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs @@ -1,9 +1,9 @@ -namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization -{ - using System.Numerics; +using System.Numerics; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization +{ public class MulUInt32 { private uint[] input; @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization [Benchmark] public void Simd() { - Vector v = new Vector(this.testValue); + var v = new Vector(this.testValue); for (int i = 0; i < this.input.Length; i += Vector.Count) { diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs index d1b70f21b..7a679c000 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs @@ -1,8 +1,8 @@ +using System.Numerics; +using BenchmarkDotNet.Attributes; + namespace ImageSharp.Benchmarks.General.Vectorization { - using System.Numerics; - using BenchmarkDotNet.Attributes; - public class MulUInt32 : SIMDBenchmarkBase.Multiply { protected override uint GetTestValue() => 42u; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs index f3853a8b1..67a8a9f39 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs @@ -1,10 +1,10 @@ -namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization -{ - using System.Numerics; - using System.Runtime.InteropServices; +using System.Numerics; +using System.Runtime.InteropServices; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization +{ public class ReinterpretUInt32AsFloat { private uint[] input; @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization [Benchmark(Baseline = true)] public void Standard() { - UIntFloatUnion u = default(UIntFloatUnion); + UIntFloatUnion u = default; for (int i = 0; i < this.input.Length; i++) { u.i = this.input[i]; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs index 76987dbd2..8fc9d9977 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs @@ -1,10 +1,10 @@ -namespace ImageSharp.Benchmarks.General.Vectorization -{ - using System.Numerics; - using System.Runtime.CompilerServices; +using System.Numerics; +using System.Runtime.CompilerServices; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace ImageSharp.Benchmarks.General.Vectorization +{ public abstract class SIMDBenchmarkBase where T : struct { @@ -19,7 +19,6 @@ namespace ImageSharp.Benchmarks.General.Vectorization protected virtual T GetTestValue() => default(T); protected virtual Vector GetTestVector() => new Vector(this.GetTestValue()); - [Params(32)] public int InputSize { get; set; } diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index f941203db..e600af785 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -16,10 +16,10 @@ - - + + - + diff --git a/tests/ImageSharp.Benchmarks/Program.cs b/tests/ImageSharp.Benchmarks/Program.cs index 4dd63067a..5caf238fb 100644 --- a/tests/ImageSharp.Benchmarks/Program.cs +++ b/tests/ImageSharp.Benchmarks/Program.cs @@ -1,15 +1,12 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// + +using System.Reflection; + +using BenchmarkDotNet.Running; namespace SixLabors.ImageSharp.Benchmarks { - using BenchmarkDotNet.Running; - - using SixLabors.ImageSharp.Formats; - using System.Reflection; - public class Program { /// diff --git a/tests/ImageSharp.Benchmarks/Samplers/Crop.cs b/tests/ImageSharp.Benchmarks/Samplers/Crop.cs index 240a277cf..4fe7a365f 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Crop.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Crop.cs @@ -1,46 +1,40 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// using SixLabors.ImageSharp.PixelFormats; -namespace SixLabors.ImageSharp.Benchmarks -{ - using System.Drawing; - using System.Drawing.Drawing2D; +using System.Drawing; +using System.Drawing.Drawing2D; - using BenchmarkDotNet.Attributes; - using SixLabors.ImageSharp.Processing; +using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.Processing; - using CoreSize = SixLabors.Primitives.Size; +using CoreSize = SixLabors.Primitives.Size; +namespace SixLabors.ImageSharp.Benchmarks +{ public class Crop : BenchmarkBase { [Benchmark(Baseline = true, Description = "System.Drawing Crop")] public Size CropSystemDrawing() { - using (Bitmap source = new Bitmap(800, 800)) + using (var source = new Bitmap(800, 800)) + using (var destination = new Bitmap(100, 100)) + using (var graphics = Graphics.FromImage(destination)) { - using (Bitmap destination = new Bitmap(100, 100)) - { - using (Graphics graphics = Graphics.FromImage(destination)) - { - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.DrawImage(source, new Rectangle(0, 0, 100, 100), 0, 0, 100, 100, GraphicsUnit.Pixel); - } - - return destination.Size; - } + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.DrawImage(source, new Rectangle(0, 0, 100, 100), 0, 0, 100, 100, GraphicsUnit.Pixel); + + return destination.Size; } } [Benchmark(Description = "ImageSharp Crop")] public CoreSize CropResizeCore() { - using (Image image = new Image(800, 800)) + using (var image = new Image(800, 800)) { image.Mutate(x => x.Crop(100, 100)); return new CoreSize(image.Width, image.Height); diff --git a/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs b/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs index 006d1b639..b36b28ef3 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/DetectEdges.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// using SixLabors.ImageSharp.PixelFormats; @@ -53,4 +51,4 @@ namespace SixLabors.ImageSharp.Benchmarks this.image.Mutate(x => x.DetectEdges(EdgeDetectionOperators.Sobel)); } } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs index 729971548..15b82e022 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs @@ -4,7 +4,6 @@ using System; using System.Buffers; using System.Numerics; -using System.Threading.Tasks; using BenchmarkDotNet.Attributes; @@ -35,7 +34,7 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Description = "ImageSharp Glow - Bulk")] public CoreSize GlowBulk() { - using (Image image = new Image(800, 800)) + using (var image = new Image(800, 800)) { this.bulk.Apply(image, image.Bounds()); return new CoreSize(image.Width, image.Height); @@ -45,7 +44,7 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Description = "ImageSharp Glow - Parallel")] public CoreSize GLowSimple() { - using (Image image = new Image(800, 800)) + using (var image = new Image(800, 800)) { this.parallel.Apply(image, image.Bounds()); return new CoreSize(image.Width, image.Height); @@ -128,7 +127,7 @@ namespace SixLabors.ImageSharp.Benchmarks int offsetX = x - startX; float distance = Vector2.Distance(centre, new Vector2(offsetX, offsetY)); Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4(); - TPixel packed = default(TPixel); + TPixel packed = default; packed.FromVector4( PremultipliedLerp( sourceColor, @@ -166,9 +165,9 @@ namespace SixLabors.ImageSharp.Benchmarks // https://en.wikipedia.org/wiki/Alpha_compositing // Vout = Vs + Vb (1 - Vsa) // Aout = Vsa + Vsb (1 - Vsa) - Vector3 inverseW = new Vector3(1 - source.W); - Vector3 xyzB = new Vector3(backdrop.X, backdrop.Y, backdrop.Z); - Vector3 xyzS = new Vector3(source.X, source.Y, source.Z); + var inverseW = new Vector3(1 - source.W); + var xyzB = new Vector3(backdrop.X, backdrop.Y, backdrop.Z); + var xyzS = new Vector3(source.X, source.Y, source.Z); return new Vector4(xyzS + (xyzB * inverseW), source.W + (backdrop.W * (1 - source.W))); } diff --git a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs index 51f3a5653..e99163f8b 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Drawing; using System.Drawing.Drawing2D; diff --git a/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs b/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs index f898576af..69ff1549b 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs @@ -1,4 +1,7 @@ -using BenchmarkDotNet.Attributes; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.Primitives; diff --git a/tests/ImageSharp.Benchmarks/Samplers/Skew.cs b/tests/ImageSharp.Benchmarks/Samplers/Skew.cs index 84819750a..559e49704 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Skew.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Skew.cs @@ -1,4 +1,7 @@ -using BenchmarkDotNet.Attributes; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.Primitives; From 5a85ea72b55255c80ffbec94ea703937759aaf2f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 15 Apr 2019 18:02:39 +1000 Subject: [PATCH 3/3] Handle incorrect colorspace metadata. Fix #882 (#885) --- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 13 ++++++------- .../Formats/Jpg/JpegDecoderTests.Images.cs | 5 ++++- tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/External | 2 +- .../issues/issue855-incorrect-colorspace.jpg | Bin 0 -> 142656 bytes 5 files changed, 12 insertions(+), 9 deletions(-) create mode 100644 tests/Images/Input/Jpg/issues/issue855-incorrect-colorspace.jpg diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 9852b36e4..6d6983f19 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -401,15 +401,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg if (this.ComponentCount == 3) { - if (this.adobe.Equals(default) || this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformYCbCr) - { - return JpegColorSpace.YCbCr; - } - - if (this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown) + if (!this.adobe.Equals(default) && this.adobe.ColorTransform == JpegConstants.Adobe.ColorTransformUnknown) { return JpegColorSpace.RGB; } + + // Some images are poorly encoded and contain incorrect colorspace transform metadata. + // We ignore that and always fall back to the default colorspace. + return JpegColorSpace.YCbCr; } if (this.ComponentCount == 4) @@ -419,7 +418,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg : JpegColorSpace.Cmyk; } - JpegThrowHelper.ThrowImageFormatException($"Unsupported color mode. Max components 4; found {this.ComponentCount}"); + JpegThrowHelper.ThrowImageFormatException($"Unsupported color mode. Supported component counts 1, 3, and 4; found {this.ComponentCount}"); return default; } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs index 8a9482607..442fcb3d1 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs @@ -31,9 +31,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Issues.ExifGetString750Load, TestImages.Jpeg.Issues.ExifGetString750Transform, - // LibJpeg can open this despite the invalid desity units. + // LibJpeg can open this despite the invalid density units. TestImages.Jpeg.Issues.Fuzz.ArgumentOutOfRangeException825B, + // LibJpeg can open this despite incorrect colorspace metadata. + TestImages.Jpeg.Issues.IncorrectColorspace855, + // High depth images TestImages.Jpeg.Baseline.Testorig12bit, }; diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 1efb9e35f..8b2fd2e7f 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -175,6 +175,7 @@ namespace SixLabors.ImageSharp.Tests public const string ExifGetString750Transform = "Jpg/issues/issue750-exif-tranform.jpg"; public const string ExifGetString750Load = "Jpg/issues/issue750-exif-load.jpg"; public const string IncorrectQuality845 = "Jpg/issues/Issue845-Incorrect-Quality99.jpg"; + public const string IncorrectColorspace855 = "Jpg/issues/issue855-incorrect-colorspace.jpg"; public static class Fuzz { diff --git a/tests/Images/External b/tests/Images/External index 94b5a8e11..802725dec 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 94b5a8e11b33ba62c15d1d03f1b8b721468764f1 +Subproject commit 802725dec2a6b1ca02f9e2f9a4c3f625583d0696 diff --git a/tests/Images/Input/Jpg/issues/issue855-incorrect-colorspace.jpg b/tests/Images/Input/Jpg/issues/issue855-incorrect-colorspace.jpg new file mode 100644 index 0000000000000000000000000000000000000000..54db7982c563d319d12de9f31270efd43f7a9244 GIT binary patch literal 142656 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

vM$WA_rF7sredq`ggY; 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 CPOC8h literal 0 HcmV?d00001