diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index ac97570941..36e27866e9 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Formats.Gif bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global; // Quantize the image returning a palette. - QuantizedFrame quantized = null; + IQuantizedFrame quantized = null; using (IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(image.GetConfiguration())) { quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.Formats.Gif stream.WriteByte(GifConstants.EndIntroducer); } - private void EncodeGlobal(Image image, QuantizedFrame quantized, int transparencyIndex, Stream stream) + private void EncodeGlobal(Image image, IQuantizedFrame quantized, int transparencyIndex, Stream stream) where TPixel : struct, IPixel { for (int i = 0; i < image.Frames.Count; i++) @@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.Formats.Gif using (IFrameQuantizer palleteFrameQuantizer = new PaletteFrameQuantizer(this.quantizer.Diffuser, quantized.Palette)) { - using (QuantizedFrame paletteQuantized = palleteFrameQuantizer.QuantizeFrame(frame)) + using (IQuantizedFrame paletteQuantized = palleteFrameQuantizer.QuantizeFrame(frame)) { this.WriteImageData(paletteQuantized, stream); } @@ -170,7 +170,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } } - private void EncodeLocal(Image image, QuantizedFrame quantized, Stream stream) + private void EncodeLocal(Image image, IQuantizedFrame quantized, Stream stream) where TPixel : struct, IPixel { ImageFrame previousFrame = null; @@ -222,7 +222,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// The . /// - private int GetTransparentIndex(QuantizedFrame quantized) + private int GetTransparentIndex(IQuantizedFrame quantized) where TPixel : struct, IPixel { // Transparent pixels are much more likely to be found at the end of a palette @@ -425,7 +425,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The pixel format. /// The to encode. /// The stream to write to. - private void WriteColorTable(QuantizedFrame image, Stream stream) + private void WriteColorTable(IQuantizedFrame image, Stream stream) where TPixel : struct, IPixel { // The maximum number of colors for the bit depth @@ -447,9 +447,9 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Writes the image pixel data to the stream. /// /// The pixel format. - /// The containing indexed pixels. + /// The containing indexed pixels. /// The stream to write to. - private void WriteImageData(QuantizedFrame image, Stream stream) + private void WriteImageData(IQuantizedFrame image, Stream stream) where TPixel : struct, IPixel { using (var encoder = new LzwEncoder(this.memoryAllocator, (byte)this.bitDepth)) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 7bdced536b..cbc35f3c3e 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -227,7 +227,7 @@ namespace SixLabors.ImageSharp.Formats.Png stream.Write(PngConstants.HeaderBytes, 0, PngConstants.HeaderBytes.Length); - QuantizedFrame quantized = null; + IQuantizedFrame quantized = null; if (this.pngColorType == PngColorType.Palette) { byte bits = (byte)this.pngBitDepth; @@ -511,7 +511,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The quantized pixels. Can be null. /// The row. /// The - private IManagedByteBuffer EncodePixelRow(ReadOnlySpan rowSpan, QuantizedFrame quantized, int row) + private IManagedByteBuffer EncodePixelRow(ReadOnlySpan rowSpan, IQuantizedFrame quantized, int row) where TPixel : struct, IPixel { switch (this.pngColorType) @@ -662,7 +662,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The containing image data. /// The quantized frame. - private void WritePaletteChunk(Stream stream, QuantizedFrame quantized) + private void WritePaletteChunk(Stream stream, IQuantizedFrame quantized) where TPixel : struct, IPixel { // Grab the palette and write it to the stream. @@ -808,7 +808,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The image. /// The quantized pixel data. Can be null. /// The stream. - private void WriteDataChunks(ImageFrame pixels, QuantizedFrame quantized, Stream stream) + private void WriteDataChunks(ImageFrame pixels, IQuantizedFrame quantized, Stream stream) where TPixel : struct, IPixel { this.bytesPerScanline = this.CalculateScanlineLength(this.width); diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizer{TPixel}.cs index d753b08a83..e6ffecc84d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizer{TPixel}.cs @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } /// - public QuantizedFrame QuantizeFrame(ImageFrame image) + public IQuantizedFrame QuantizeFrame(ImageFrame image) { Guard.NotNull(image, nameof(image)); diff --git a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs index f0b68b3a08..54dabab0ae 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IFrameQuantizer{TPixel}.cs @@ -31,6 +31,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// A representing a quantized version of the image pixels. /// - QuantizedFrame QuantizeFrame(ImageFrame image); + IQuantizedFrame QuantizeFrame(ImageFrame image); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/IQuantizedFrame{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/IQuantizedFrame{TPixel}.cs new file mode 100644 index 0000000000..42016459be --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/IQuantizedFrame{TPixel}.cs @@ -0,0 +1,38 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// Defines an abstraction to represent a quantized image frame where the pixels indexed by a color palette. + /// + /// The pixel format. + public interface IQuantizedFrame : IDisposable + where TPixel : struct, IPixel + { + /// + /// Gets the width of this . + /// + int Width { get; } + + /// + /// Gets the height of this . + /// + int Height { get; } + + /// + /// Gets the color palette of this . + /// + ReadOnlyMemory Palette { get; } + + /// + /// Gets the pixels of this . + /// + /// The The pixel span. + ReadOnlySpan GetPixelSpan(); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs index 21071dd8a0..5cb45e8d70 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs @@ -31,8 +31,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - using (IFrameQuantizer executor = this.quantizer.CreateFrameQuantizer(configuration)) - using (QuantizedFrame quantized = executor.QuantizeFrame(source)) + using (IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(configuration)) + using (IQuantizedFrame quantized = frameQuantizer.QuantizeFrame(source)) { int paletteCount = quantized.Palette.Length - 1; diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrameExtensions.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrameExtensions.cs new file mode 100644 index 0000000000..fa3d36e10a --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrameExtensions.cs @@ -0,0 +1,29 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// Contains extension methods for . + /// + public static class QuantizedFrameExtensions + { + /// + /// Gets the representation of the pixels as a of contiguous memory + /// at row beginning from the the first pixel on that row. + /// + /// The . + /// The row. + /// The pixel type. + /// The pixel row as a . + [MethodImpl(InliningOptions.ShortMethod)] + public static ReadOnlySpan GetRowSpan(this IQuantizedFrame frame, int rowIndex) + where TPixel : struct, IPixel + => frame.GetPixelSpan().Slice(rowIndex * frame.Width, frame.Width); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs index a4d06ac2e2..cbea82c1f3 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs @@ -8,14 +8,13 @@ using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; -// TODO: Consider pooling the TPixel palette also. For Rgba48+ this would end up on th LOH if 256 colors. namespace SixLabors.ImageSharp.Processing.Processors.Quantization { /// /// Represents a quantized image frame where the pixels indexed by a color palette. /// /// The pixel format. - public class QuantizedFrame : IDisposable + public class QuantizedFrame : IQuantizedFrame where TPixel : struct, IPixel { private IMemoryOwner pixels; @@ -60,15 +59,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization [MethodImpl(InliningOptions.ShortMethod)] public ReadOnlySpan GetPixelSpan() => this.pixels.GetSpan(); - /// - /// Gets the representation of the pixels as a of contiguous memory - /// at row beginning from the the first pixel on that row. - /// - /// The row. - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public ReadOnlySpan GetRowSpan(int rowIndex) => this.GetPixelSpan().Slice(rowIndex * this.Width, this.Width); - /// public void Dispose() { diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index b0de058f80..04e9803af4 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { - QuantizedFrame quantized = + IQuantizedFrame quantized = quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); int index = this.GetTransparentIndex(quantized); @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { - QuantizedFrame quantized = + IQuantizedFrame quantized = quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); int index = this.GetTransparentIndex(quantized); @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests } } - private int GetTransparentIndex(QuantizedFrame quantized) + private int GetTransparentIndex(IQuantizedFrame quantized) where TPixel : struct, IPixel { // Transparent pixels are much more likely to be found at the end of a palette diff --git a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs index 716273699e..a1de7fd4b9 100644 --- a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization 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])) + using (IQuantizedFrame result = quantizer.CreateFrameQuantizer(config).QuantizeFrame(image.Frames[0])) { Assert.Equal(1, result.Palette.Length); Assert.Equal(1, result.GetPixelSpan().Length); @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization 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])) + using (IQuantizedFrame result = quantizer.CreateFrameQuantizer(config).QuantizeFrame(image.Frames[0])) { Assert.Equal(1, result.Palette.Length); Assert.Equal(1, result.GetPixelSpan().Length); @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization Configuration config = Configuration.Default; var quantizer = new WuQuantizer(false); using (IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config)) - using (QuantizedFrame result = frameQuantizer.QuantizeFrame(image.Frames[0])) + using (IQuantizedFrame result = frameQuantizer.QuantizeFrame(image.Frames[0])) { Assert.Equal(256, result.Palette.Length); Assert.Equal(256, result.GetPixelSpan().Length); @@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization Configuration config = Configuration.Default; var quantizer = new WuQuantizer(false); using (IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config)) - using (QuantizedFrame result = frameQuantizer.QuantizeFrame(image.Frames[0])) + using (IQuantizedFrame result = frameQuantizer.QuantizeFrame(image.Frames[0])) { Assert.Equal(48, result.Palette.Length); } @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Tests.Quantization var quantizer = new WuQuantizer(false); using (IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(config)) - using (QuantizedFrame result = frameQuantizer.QuantizeFrame(image.Frames[0])) + using (IQuantizedFrame result = frameQuantizer.QuantizeFrame(image.Frames[0])) { Assert.Equal(4 * 8, result.Palette.Length); Assert.Equal(256, result.GetPixelSpan().Length);