diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 2770790a2..9270bb6b1 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -233,7 +233,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { Span rgbaSpan = rgbaBuffer.GetSpan(); ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan); - PixelOperations.Instance.ToRgba32(this.configuration, quantized.Palette, rgbaSpan); + PixelOperations.Instance.ToRgba32(this.configuration, quantized.Palette.Span, rgbaSpan); for (int i = quantized.Palette.Length - 1; i >= 0; i--) { @@ -436,7 +436,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { PixelOperations.Instance.ToRgb24Bytes( this.configuration, - image.Palette.AsSpan(), + image.Palette.Span, colorTable.GetSpan(), pixelCount); stream.Write(colorTable.Array, 0, colorTableLength); diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 7415b0753..db0c7f258 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -666,7 +666,7 @@ namespace SixLabors.ImageSharp.Formats.Png where TPixel : struct, IPixel { // Grab the palette and write it to the stream. - TPixel[] palette = quantized.Palette; + ReadOnlySpan palette = quantized.Palette.Span; int paletteLength = Math.Min(palette.Length, 256); int colorTableLength = paletteLength * 3; bool anyAlpha = false; diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizer{TPixel}.cs index 6d8136513..eac31b21d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizer{TPixel}.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Numerics; using System.Runtime.CompilerServices; + using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Dithering; @@ -52,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization this.Dither = this.Diffuser != null; this.singlePass = singlePass; } - + /// /// Initializes a new instance of the class. /// @@ -73,10 +74,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } /// - public bool Dither { get; } + public IErrorDiffuser Diffuser { get; } /// - public IErrorDiffuser Diffuser { get; } + public bool Dither { get; } + + /// + public virtual void Dispose() + { + } /// public virtual QuantizedFrame QuantizeFrame(ImageFrame image) @@ -98,14 +104,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // Collect the palette. Required before the second pass runs. ReadOnlyMemory palette = this.GetPalette(); this.paletteVector = new Vector4[palette.Length]; - PixelOperations.Instance.ToVector4(image.Configuration, palette.Span, (Span)this.paletteVector, PixelConversionModifiers.Scale); + PixelOperations.Instance.ToVector4( + image.Configuration, + palette.Span, + (Span)this.paletteVector, + PixelConversionModifiers.Scale); - // TODO: Pass ReadOnlyMemory instead of array! - var quantizedFrame = new QuantizedFrame( - image.MemoryAllocator, - width, - height, - palette.Span.ToArray()); + var quantizedFrame = new QuantizedFrame(image.MemoryAllocator, width, height, palette); if (this.Dither) { @@ -123,11 +128,6 @@ 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. /// @@ -139,19 +139,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } /// - /// Execute a second pass through the image to assign the pixels to a palette entry. + /// Returns the closest color from the palette to the given color by calculating the + /// Euclidean distance in the Rgba colorspace. /// - /// The source image. - /// The output pixel array. - /// The output color palette. - /// The width in pixels of the image. - /// The height in pixels of the image. - protected abstract void SecondPass( - ImageFrame source, - Span output, - ReadOnlySpan palette, - int width, - int height); + /// The color. + /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected byte GetClosestPixel(ref TPixel pixel) + { + // Check if the color is in the lookup table + if (this.distanceCache.TryGetValue(pixel, out byte value)) + { + return value; + } + + return this.GetClosestPixelSlow(ref pixel); + } /// /// Retrieve the palette for the quantized image. @@ -185,22 +188,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } /// - /// Returns the closest color from the palette to the given color by calculating the - /// Euclidean distance in the Rgba colorspace. + /// Execute a second pass through the image to assign the pixels to a palette entry. /// - /// The color. - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected byte GetClosestPixel(ref TPixel pixel) - { - // Check if the color is in the lookup table - if (this.distanceCache.TryGetValue(pixel, out byte value)) - { - return value; - } - - return this.GetClosestPixelSlow(ref pixel); - } + /// The source image. + /// The output pixel array. + /// The output color palette. + /// The width in pixels of the image. + /// The height in pixels of the image. + protected abstract void SecondPass( + ImageFrame source, + Span output, + ReadOnlySpan palette, + int width, + int height); [MethodImpl(MethodImplOptions.NoInlining)] private byte GetClosestPixelSlow(ref TPixel pixel) diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs index b52343a2a..4f134d98d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs @@ -43,12 +43,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { Span row = source.GetPixelRowSpan(y); ReadOnlySpan quantizedPixelSpan = quantized.GetPixelSpan(); + + ReadOnlySpan paletteSpan = quantized.Palette.Span; + int yy = y * source.Width; for (int x = 0; x < source.Width; x++) { int i = x + yy; - row[x] = quantized.Palette[Math.Min(paletteCount, quantizedPixelSpan[i])]; + row[x] = paletteSpan[Math.Min(paletteCount, quantizedPixelSpan[i])]; } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs index 38862ef44..ae5b5dda8 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The image width. /// The image height. /// The color palette. - public QuantizedFrame(MemoryAllocator memoryAllocator, int width, int height, TPixel[] palette) + public QuantizedFrame(MemoryAllocator memoryAllocator, int width, int height, ReadOnlyMemory palette) { Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Gets the color palette of this . /// - public TPixel[] Palette { get; private set; } + public ReadOnlyMemory Palette { get; private set; } /// /// Gets the pixels of this . diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index a0d7869e3..b0de058f8 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -1,6 +1,8 @@ // 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.Quantization; @@ -85,9 +87,10 @@ namespace SixLabors.ImageSharp.Tests // Transparent pixels are much more likely to be found at the end of a palette int index = -1; Rgba32 trans = default; - for (int i = quantized.Palette.Length - 1; i >= 0; i--) + ReadOnlySpan paletteSpan = quantized.Palette.Span; + for (int i = paletteSpan.Length - 1; i >= 0; i--) { - quantized.Palette[i].ToRgba32(ref trans); + paletteSpan[i].ToRgba32(ref trans); if (trans.Equals(default)) { diff --git a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs index 3eacd74ea..716273699 100644 --- a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization Assert.Equal(1, result.Palette.Length); Assert.Equal(1, result.GetPixelSpan().Length); - Assert.Equal(Rgba32.Black, result.Palette[0]); + Assert.Equal(Rgba32.Black, result.Palette.Span[0]); Assert.Equal(0, result.GetPixelSpan()[0]); } } @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization Assert.Equal(1, result.Palette.Length); Assert.Equal(1, result.GetPixelSpan().Length); - Assert.Equal(default, result.Palette[0]); + Assert.Equal(default, result.Palette.Span[0]); Assert.Equal(0, result.GetPixelSpan()[0]); } } @@ -82,6 +82,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization var actualImage = new Image(1, 256); + ReadOnlySpan paletteSpan = result.Palette.Span; int paletteCount = result.Palette.Length - 1; for (int y = 0; y < actualImage.Height; y++) { @@ -92,7 +93,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization for (int x = 0; x < actualImage.Width; x++) { int i = x + yy; - row[x] = result.Palette[Math.Min(paletteCount, quantizedPixelSpan[i])]; + row[x] = paletteSpan[Math.Min(paletteCount, quantizedPixelSpan[i])]; } } @@ -146,6 +147,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization Assert.Equal(4 * 8, result.Palette.Length); Assert.Equal(256, result.GetPixelSpan().Length); + ReadOnlySpan paletteSpan = result.Palette.Span; int paletteCount = result.Palette.Length - 1; for (int y = 0; y < actualImage.Height; y++) { @@ -156,7 +158,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization for (int x = 0; x < actualImage.Width; x++) { int i = x + yy; - row[x] = result.Palette[Math.Min(paletteCount, quantizedPixelSpan[i])]; + row[x] = paletteSpan[Math.Min(paletteCount, quantizedPixelSpan[i])]; } } }