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);
}
}