From 316d4cc5549b4fc53df1e9f1ef616178a4e9c751 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 17 Jun 2021 10:54:50 +0200 Subject: [PATCH] Use bulk conversion to bgra --- .../Formats/WebP/Lossless/Vp8LEncoder.cs | 71 +++++++++++-------- .../Formats/WebP/WebpEncoderCore.cs | 2 +- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs index 3b6ad45ebe..1b00227483 100644 --- a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs @@ -19,6 +19,16 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless /// internal class Vp8LEncoder : IDisposable { + /// + /// The to use for buffer allocations. + /// + private readonly MemoryAllocator memoryAllocator; + + /// + /// The global configuration. + /// + private readonly Configuration configuration; + /// /// Maximum number of reference blocks the image will be segmented into. /// @@ -29,11 +39,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless /// private const int MinBlockSize = 256; - /// - /// The to use for buffer allocations. - /// - private readonly MemoryAllocator memoryAllocator; - /// /// A bit writer for writing lossless webp streams. /// @@ -59,15 +64,18 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless /// Initializes a new instance of the class. /// /// The memory allocator. + /// The global configuration. /// The width of the input image. /// The height of the input image. /// The encoding quality. /// Quality/speed trade-off (0=fast, 6=slower-better). - public Vp8LEncoder(MemoryAllocator memoryAllocator, int width, int height, int quality, int method) + public Vp8LEncoder(MemoryAllocator memoryAllocator, Configuration configuration, int width, int height, int quality, int method) { int pixelCount = width * height; int initialSize = pixelCount * 2; + this.memoryAllocator = memoryAllocator; + this.configuration = configuration; this.quality = Numerics.Clamp(quality, 0, 100); this.method = Numerics.Clamp(method, 0, 6); this.bitWriter = new Vp8LBitWriter(initialSize); @@ -75,7 +83,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless this.Palette = memoryAllocator.Allocate(WebpConstants.MaxPaletteSize); this.Refs = new Vp8LBackwardRefs[3]; this.HashChain = new Vp8LHashChain(pixelCount); - this.memoryAllocator = memoryAllocator; // We round the block size up, so we're guaranteed to have at most MaxRefsBlockPerImage blocks used: int refsBlockSize = ((pixelCount - 1) / MaxRefsBlockPerImage) + 1; @@ -230,13 +237,16 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless // Convert image pixels to bgra array. Span bgra = this.Bgra.GetSpan(); + using IMemoryOwner bgraRowBuffer = this.memoryAllocator.Allocate(width); + Span bgraRow = bgraRowBuffer.GetSpan(); int idx = 0; for (int y = 0; y < height; y++) { Span rowSpan = image.GetPixelRowSpan(y); - for (int x = 0; x < rowSpan.Length; x++) + PixelOperations.Instance.ToBgra32(this.configuration, rowSpan, bgraRow); + for (int x = 0; x < width; x++) { - bgra[idx++] = ToBgra32(rowSpan[x]).PackedValue; + bgra[idx++] = bgraRow[x].PackedValue; } } @@ -933,18 +943,26 @@ 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; - Bgra32 pixPrev = ToBgra32(image.GetPixelRowSpan(0)[0]); // Skip the first pixel. - Span prevRow = null; + 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; for (int y = 0; y < height; y++) { - Span currentRow = image.GetPixelRowSpan(y); + Span pixelRow = image.GetPixelRowSpan(y); + PixelOperations.Instance.ToBgra32(this.configuration, pixelRow, currentRow); for (int x = 0; x < width; x++) { - Bgra32 pix = ToBgra32(currentRow[x]); + Bgra32 pix = currentRow[x]; uint pixDiff = LosslessUtils.SubPixels(pix.PackedValue, pixPrev.PackedValue); pixPrev = pix; - if ((pixDiff == 0) || (prevRow != null && pix == ToBgra32(prevRow[x]))) + if ((pixDiff == 0) || (prevRow != null && pix == prevRow[x])) { continue; } @@ -1110,13 +1128,17 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless private int GetColorPalette(Image image, Span palette) where TPixel : unmanaged, IPixel { - var colors = new HashSet(); + 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++) { Span rowSpan = image.GetPixelRowSpan(y); - for (int x = 0; x < rowSpan.Length; x++) + PixelOperations.Instance.ToBgra32(this.configuration, rowSpan, bgraRow); + for (int x = 0; x < width; x++) { - colors.Add(rowSpan[x]); + colors.Add(bgraRow[x]); if (colors.Count > WebpConstants.MaxPaletteSize) { // Exact count is not needed, because a palette will not be used then anyway. @@ -1126,12 +1148,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()) { - Bgra32 bgra = ToBgra32(colorEnumerator.Current); - palette[idx++] = bgra.PackedValue; + palette[idx++] = colorEnumerator.Current.PackedValue; } return colors.Count; @@ -1591,16 +1612,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless return res; } - [MethodImpl(InliningOptions.ShortMethod)] - private static Bgra32 ToBgra32(TPixel color) - where TPixel : unmanaged, IPixel - { - Rgba32 rgba = default; - color.ToRgba32(ref rgba); - var bgra = new Bgra32(rgba.R, rgba.G, rgba.B, rgba.A); - return bgra; - } - [MethodImpl(InliningOptions.ShortMethod)] private static void AddSingle(uint p, Span a, Span r, Span g, Span b) { diff --git a/src/ImageSharp/Formats/WebP/WebpEncoderCore.cs b/src/ImageSharp/Formats/WebP/WebpEncoderCore.cs index 985300a56d..4c405b262a 100644 --- a/src/ImageSharp/Formats/WebP/WebpEncoderCore.cs +++ b/src/ImageSharp/Formats/WebP/WebpEncoderCore.cs @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Formats.Webp } else { - var enc = new Vp8LEncoder(this.memoryAllocator, image.Width, image.Height, this.quality, this.method); + var enc = new Vp8LEncoder(this.memoryAllocator, this.configuration, image.Width, image.Height, this.quality, this.method); enc.Encode(image, stream); } }