diff --git a/src/ImageSharp/Formats/WebP/AlphaDecoder.cs b/src/ImageSharp/Formats/WebP/AlphaDecoder.cs index 8a276cebc3..f386c42da5 100644 --- a/src/ImageSharp/Formats/WebP/AlphaDecoder.cs +++ b/src/ImageSharp/Formats/WebP/AlphaDecoder.cs @@ -22,7 +22,8 @@ namespace SixLabors.ImageSharp.Formats.WebP /// The (maybe compressed) alpha data. /// The first byte of the alpha image stream contains information on ow to decode the stream. /// Used for allocating memory during decoding. - public AlphaDecoder(int width, int height, byte[] data, byte alphaChunkHeader, MemoryAllocator memoryAllocator) + /// The configuration. + public AlphaDecoder(int width, int height, byte[] data, byte alphaChunkHeader, MemoryAllocator memoryAllocator, Configuration configuration) { this.Width = width; this.Height = height; @@ -59,7 +60,7 @@ namespace SixLabors.ImageSharp.Formats.WebP if (this.Compressed) { var bitReader = new Vp8LBitReader(data); - this.LosslessDecoder = new WebPLosslessDecoder(bitReader, memoryAllocator); + this.LosslessDecoder = new WebPLosslessDecoder(bitReader, memoryAllocator, configuration); this.LosslessDecoder.DecodeImageStream(this.Vp8LDec, width, height, true); } } diff --git a/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs b/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs index a9312f19c7..f188d7d7b7 100644 --- a/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs +++ b/src/ImageSharp/Formats/WebP/WebPDecoderCore.cs @@ -89,12 +89,12 @@ namespace SixLabors.ImageSharp.Formats.WebP Buffer2D pixels = image.GetRootFramePixelBuffer(); if (imageInfo.IsLossLess) { - var losslessDecoder = new WebPLosslessDecoder(imageInfo.Vp8LBitReader, this.memoryAllocator); + var losslessDecoder = new WebPLosslessDecoder(imageInfo.Vp8LBitReader, this.memoryAllocator, this.configuration); losslessDecoder.Decode(pixels, image.Width, image.Height); } else { - var lossyDecoder = new WebPLossyDecoder(imageInfo.Vp8BitReader, this.memoryAllocator); + var lossyDecoder = new WebPLossyDecoder(imageInfo.Vp8BitReader, this.memoryAllocator, this.configuration); lossyDecoder.Decode(pixels, image.Width, image.Height, imageInfo); } diff --git a/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs b/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs index 6ca54690fc..5bb7befaf4 100644 --- a/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs +++ b/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs @@ -27,6 +27,16 @@ namespace SixLabors.ImageSharp.Formats.WebP /// private readonly Vp8LBitReader bitReader; + /// + /// The global configuration. + /// + private readonly Configuration configuration; + + /// + /// Used for allocating memory during processing operations. + /// + private readonly MemoryAllocator memoryAllocator; + private static readonly int BitsSpecialMarker = 0x100; private static readonly int NumArgbCacheRows = 16; @@ -62,20 +72,17 @@ namespace SixLabors.ImageSharp.Formats.WebP 0, 1, 1, 1, 0 }; - /// - /// Used for allocating memory during processing operations. - /// - private readonly MemoryAllocator memoryAllocator; - /// /// Initializes a new instance of the class. /// /// Bitreader to read from the stream. /// Used for allocating memory during processing operations. - public WebPLosslessDecoder(Vp8LBitReader bitReader, MemoryAllocator memoryAllocator) + /// The configuration. + public WebPLosslessDecoder(Vp8LBitReader bitReader, MemoryAllocator memoryAllocator, Configuration configuration) { this.bitReader = bitReader; this.memoryAllocator = memoryAllocator; + this.configuration = configuration; } /// @@ -181,25 +188,21 @@ namespace SixLabors.ImageSharp.Formats.WebP where TPixel : struct, IPixel { Span pixelData = decoder.Pixels.GetSpan(); + int width = decoder.Width; // Apply reverse transformations, if any are present. this.ApplyInverseTransforms(decoder, pixelData); - TPixel color = default; + Span pixelDataAsBytes = MemoryMarshal.Cast(pixelData); for (int y = 0; y < decoder.Height; y++) { - Span pixelRow = pixels.GetRowSpan(y); - for (int x = 0; x < decoder.Width; x++) - { - int idx = (y * decoder.Width) + x; - uint pixel = pixelData[idx]; - byte a = (byte)((pixel & 0xFF000000) >> 24); - byte r = (byte)((pixel & 0xFF0000) >> 16); - byte g = (byte)((pixel & 0xFF00) >> 8); - byte b = (byte)(pixel & 0xFF); - color.FromRgba32(new Rgba32(r, g, b, a)); - pixelRow[x] = color; - } + Span row = pixelDataAsBytes.Slice(y * width * 4, width * 4); + Span pixelSpan = pixels.GetRowSpan(y); + PixelOperations.Instance.FromBgra32Bytes( + this.configuration, + row, + pixelSpan, + width); } } diff --git a/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs b/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs index 03faaaa7ca..4e06b441fe 100644 --- a/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs +++ b/src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs @@ -24,15 +24,22 @@ namespace SixLabors.ImageSharp.Formats.WebP /// private readonly MemoryAllocator memoryAllocator; + /// + /// The global configuration. + /// + private readonly Configuration configuration; + /// /// Initializes a new instance of the class. /// /// Bitreader to read from the stream. /// Used for allocating memory during processing operations. - public WebPLossyDecoder(Vp8BitReader bitReader, MemoryAllocator memoryAllocator) + /// The configuration. + public WebPLossyDecoder(Vp8BitReader bitReader, MemoryAllocator memoryAllocator, Configuration configuration) { - this.memoryAllocator = memoryAllocator; this.bitReader = bitReader; + this.memoryAllocator = memoryAllocator; + this.configuration = configuration; } public void Decode(Buffer2D pixels, int width, int height, WebPImageInfo info) @@ -85,7 +92,8 @@ namespace SixLabors.ImageSharp.Formats.WebP height, info.Features.AlphaData, info.Features.AlphaChunkHeader, - this.memoryAllocator)) + this.memoryAllocator, + this.configuration)) { alphaDecoder.Decode(); this.DecodePixelValues(width, height, decoder.Pixels.Memory.Span, pixels, alphaDecoder.Alpha); @@ -101,39 +109,38 @@ namespace SixLabors.ImageSharp.Formats.WebP private void DecodePixelValues(int width, int height, Span pixelData, Buffer2D pixels, IMemoryOwner alpha = null) where TPixel : struct, IPixel { - TPixel color = default; - bool hasAlpha = false; - Span alphaSpan = null; if (alpha != null) { - hasAlpha = true; - alphaSpan = alpha.Memory.Span; - } - - for (int y = 0; y < height; y++) - { - Span pixelRow = pixels.GetRowSpan(y); - for (int x = 0; x < width; x++) + TPixel color = default; + Span alphaSpan = alpha.Memory.Span; + for (int y = 0; y < height; y++) { - int offset = (y * width) + x; - int idxBgr = offset * 3; - byte b = pixelData[idxBgr]; - byte g = pixelData[idxBgr + 1]; - byte r = pixelData[idxBgr + 2]; - - // TODO: use bulk conversion here. - if (hasAlpha) + Span pixelRow = pixels.GetRowSpan(y); + for (int x = 0; x < width; x++) { + int offset = (y * width) + x; + int idxBgr = offset * 3; + byte b = pixelData[idxBgr]; + byte g = pixelData[idxBgr + 1]; + byte r = pixelData[idxBgr + 2]; byte a = alphaSpan[offset]; color.FromBgra32(new Bgra32(r, g, b, a)); + pixelRow[x] = color; } - else - { - color.FromBgr24(new Bgr24(r, g, b)); - } - - pixelRow[x] = color; } + + return; + } + + for (int y = 0; y < height; y++) + { + Span row = pixelData.Slice(y * width * 3, width * 3); + Span pixelSpan = pixels.GetRowSpan(y); + PixelOperations.Instance.FromBgr24Bytes( + this.configuration, + row, + pixelSpan, + width); } }