diff --git a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs index 1b00227483..a486e9557c 100644 --- a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs @@ -251,7 +251,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless } // Analyze image (entropy, numPalettes etc). - CrunchConfig[] crunchConfigs = this.EncoderAnalyze(image, out bool redAndBlueAlwaysZero); + CrunchConfig[] crunchConfigs = this.EncoderAnalyze(bgra, width, height, out bool redAndBlueAlwaysZero); int bestSize = 0; Vp8LBitWriter bitWriterInit = this.bitWriter; @@ -340,14 +340,14 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless /// /// Analyzes the image and decides which transforms should be used. /// - private CrunchConfig[] EncoderAnalyze(Image image, out bool redAndBlueAlwaysZero) - where TPixel : unmanaged, IPixel + /// The image as packed bgra values. + /// The image width. + /// The image height. + /// Indicates if red and blue are always zero. + private CrunchConfig[] EncoderAnalyze(Span bgra, int width, int height, out bool redAndBlueAlwaysZero) { - int width = image.Width; - int height = image.Height; - // Check if we only deal with a small number of colors and should use a palette. - bool usePalette = this.AnalyzeAndCreatePalette(image); + bool usePalette = this.AnalyzeAndCreatePalette(bgra, width, height); // Empirical bit sizes. this.HistoBits = GetHistoBits(this.method, usePalette, width, height); @@ -355,7 +355,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless // Try out multiple LZ77 on images with few colors. int nlz77s = (this.PaletteSize > 0 && this.PaletteSize <= 16) ? 2 : 1; - EntropyIx entropyIdx = this.AnalyzeEntropy(image, usePalette, this.PaletteSize, this.TransformBits, out redAndBlueAlwaysZero); + EntropyIx entropyIdx = this.AnalyzeEntropy(bgra, width, height, usePalette, this.PaletteSize, this.TransformBits, out redAndBlueAlwaysZero); bool doNotCache = false; var crunchConfigs = new List(); @@ -921,19 +921,16 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless /// /// Analyzes the entropy of the input image to determine which transforms to use during encoding the image. /// - /// The pixel type of the image. - /// The image to analyze. + /// The image to analyze as a bgra span. + /// The image width. + /// The image height. /// Indicates whether a palette should be used. /// The palette size. /// The transformation bits. /// Indicates if red and blue are always zero. /// The entropy mode to use. - private EntropyIx AnalyzeEntropy(Image image, bool usePalette, int paletteSize, int transformBits, out bool redAndBlueAlwaysZero) - where TPixel : unmanaged, IPixel + private EntropyIx AnalyzeEntropy(Span bgra, int width, int height, bool usePalette, int paletteSize, int transformBits, out bool redAndBlueAlwaysZero) { - int width = image.Width; - int height = image.Height; - if (usePalette && paletteSize <= 16) { // In the case of small palettes, we pack 2, 4 or 8 pixels together. In @@ -943,24 +940,16 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless } using IMemoryOwner histoBuffer = this.memoryAllocator.Allocate((int)HistoIx.HistoTotal * 256); - using IMemoryOwner bgraBuffer = this.memoryAllocator.Allocate(width); - Span currentRow = bgraBuffer.GetSpan(); Span histo = histoBuffer.Memory.Span; - TPixel firstPixel = image.GetPixelRowSpan(0)[0]; - Bgra32 bgra = default; - Rgba32 rgba = default; - firstPixel.ToRgba32(ref rgba); - bgra.FromRgba32(rgba); - Bgra32 pixPrev = bgra; // Skip the first pixel. - Span prevRow = null; + uint pixPrev = bgra[0]; // Skip the first pixel. + Span prevRow = null; for (int y = 0; y < height; y++) { - Span pixelRow = image.GetPixelRowSpan(y); - PixelOperations.Instance.ToBgra32(this.configuration, pixelRow, currentRow); + Span currentRow = bgra.Slice(y * width, width); for (int x = 0; x < width; x++) { - Bgra32 pix = currentRow[x]; - uint pixDiff = LosslessUtils.SubPixels(pix.PackedValue, pixPrev.PackedValue); + uint pix = currentRow[x]; + uint pixDiff = LosslessUtils.SubPixels(pix, pixPrev); pixPrev = pix; if ((pixDiff == 0) || (prevRow != null && pix == prevRow[x])) { @@ -968,7 +957,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless } AddSingle( - pix.PackedValue, + pix, histo.Slice((int)HistoIx.HistoAlpha * 256), histo.Slice((int)HistoIx.HistoRed * 256), histo.Slice((int)HistoIx.HistoGreen * 256), @@ -980,7 +969,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless histo.Slice((int)HistoIx.HistoGreenPred * 256), histo.Slice((int)HistoIx.HistoBluePred * 256)); AddSingleSubGreen( - pix.PackedValue, + pix, histo.Slice((int)HistoIx.HistoRedSubGreen * 256), histo.Slice((int)HistoIx.HistoBlueSubGreen * 256)); AddSingleSubGreen( @@ -989,7 +978,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless histo.Slice((int)HistoIx.HistoBluePredSubGreen * 256)); // Approximate the palette by the entropy of the multiplicative hash. - uint hash = HashPix(pix.PackedValue); + uint hash = HashPix(pix); histo[((int)HistoIx.HistoPalette * 256) + (int)hash]++; } @@ -1094,12 +1083,14 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless /// If number of colors in the image is less than or equal to MaxPaletteSize, /// creates a palette and returns true, else returns false. /// + /// The image as packed bgra values. + /// The image width. + /// The image height. /// true, if a palette should be used. - private bool AnalyzeAndCreatePalette(Image image) - where TPixel : unmanaged, IPixel + private bool AnalyzeAndCreatePalette(Span bgra, int width, int height) { Span palette = this.Palette.Memory.Span; - this.PaletteSize = this.GetColorPalette(image, palette); + this.PaletteSize = this.GetColorPalette(bgra, width, height, palette); if (this.PaletteSize > WebpConstants.MaxPaletteSize) { this.PaletteSize = 0; @@ -1121,21 +1112,17 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless /// /// Gets the color palette. /// - /// The pixel type of the image. - /// The image to get the palette from. + /// The image to get the palette from as packed bgra values. + /// The image width. + /// The image height. /// The span to store the palette into. /// The number of palette entries. - private int GetColorPalette(Image image, Span palette) - where TPixel : unmanaged, IPixel + private int GetColorPalette(Span bgra, int width, int height, Span palette) { - int width = image.Width; - var colors = new HashSet(); - using IMemoryOwner bgraRowBuffer = this.memoryAllocator.Allocate(width); - Span bgraRow = bgraRowBuffer.GetSpan(); - for (int y = 0; y < image.Height; y++) + var colors = new HashSet(); + for (int y = 0; y < height; y++) { - Span rowSpan = image.GetPixelRowSpan(y); - PixelOperations.Instance.ToBgra32(this.configuration, rowSpan, bgraRow); + Span bgraRow = bgra.Slice(y * width, width); for (int x = 0; x < width; x++) { colors.Add(bgraRow[x]); @@ -1148,11 +1135,11 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless } // Fill the colors into the palette. - using HashSet.Enumerator colorEnumerator = colors.GetEnumerator(); + using HashSet.Enumerator colorEnumerator = colors.GetEnumerator(); int idx = 0; while (colorEnumerator.MoveNext()) { - palette[idx++] = colorEnumerator.Current.PackedValue; + palette[idx++] = colorEnumerator.Current; } return colors.Count;