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/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/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.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/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 cb2481dbf..cf47202cc 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; using System.Globalization; 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; 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/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..8b2fd2e7f 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"; @@ -174,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/Input/Jpg/issues/issue855-incorrect-colorspace.jpg b/tests/Images/Input/Jpg/issues/issue855-incorrect-colorspace.jpg new file mode 100644 index 000000000..77c032768 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/issue855-incorrect-colorspace.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fabf628f032dce427a6a0e0f252404d66dc4ce2cd7ee2d7ec72a1fbe79c625d0 +size 142656 diff --git a/tests/Images/Input/Png/low-variance.png b/tests/Images/Input/Png/low-variance.png new file mode 100644 index 000000000..7d8b1043e --- /dev/null +++ b/tests/Images/Input/Png/low-variance.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:70c224ef674b546db0ec3281008bb6e2b879e95b0be5625f0af8aff980eee583 +size 7844