Browse Source

Use bulk conversion to bgra

pull/1552/head
Brian Popow 5 years ago
parent
commit
316d4cc554
  1. 71
      src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
  2. 2
      src/ImageSharp/Formats/WebP/WebpEncoderCore.cs

71
src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs

@ -19,6 +19,16 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// </summary> /// </summary>
internal class Vp8LEncoder : IDisposable internal class Vp8LEncoder : IDisposable
{ {
/// <summary>
/// The <see cref="MemoryAllocator"/> to use for buffer allocations.
/// </summary>
private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// The global configuration.
/// </summary>
private readonly Configuration configuration;
/// <summary> /// <summary>
/// Maximum number of reference blocks the image will be segmented into. /// Maximum number of reference blocks the image will be segmented into.
/// </summary> /// </summary>
@ -29,11 +39,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// </summary> /// </summary>
private const int MinBlockSize = 256; private const int MinBlockSize = 256;
/// <summary>
/// The <see cref="MemoryAllocator"/> to use for buffer allocations.
/// </summary>
private readonly MemoryAllocator memoryAllocator;
/// <summary> /// <summary>
/// A bit writer for writing lossless webp streams. /// A bit writer for writing lossless webp streams.
/// </summary> /// </summary>
@ -59,15 +64,18 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// Initializes a new instance of the <see cref="Vp8LEncoder"/> class. /// Initializes a new instance of the <see cref="Vp8LEncoder"/> class.
/// </summary> /// </summary>
/// <param name="memoryAllocator">The memory allocator.</param> /// <param name="memoryAllocator">The memory allocator.</param>
/// <param name="configuration">The global configuration.</param>
/// <param name="width">The width of the input image.</param> /// <param name="width">The width of the input image.</param>
/// <param name="height">The height of the input image.</param> /// <param name="height">The height of the input image.</param>
/// <param name="quality">The encoding quality.</param> /// <param name="quality">The encoding quality.</param>
/// <param name="method">Quality/speed trade-off (0=fast, 6=slower-better).</param> /// <param name="method">Quality/speed trade-off (0=fast, 6=slower-better).</param>
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 pixelCount = width * height;
int initialSize = pixelCount * 2; int initialSize = pixelCount * 2;
this.memoryAllocator = memoryAllocator;
this.configuration = configuration;
this.quality = Numerics.Clamp(quality, 0, 100); this.quality = Numerics.Clamp(quality, 0, 100);
this.method = Numerics.Clamp(method, 0, 6); this.method = Numerics.Clamp(method, 0, 6);
this.bitWriter = new Vp8LBitWriter(initialSize); this.bitWriter = new Vp8LBitWriter(initialSize);
@ -75,7 +83,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
this.Palette = memoryAllocator.Allocate<uint>(WebpConstants.MaxPaletteSize); this.Palette = memoryAllocator.Allocate<uint>(WebpConstants.MaxPaletteSize);
this.Refs = new Vp8LBackwardRefs[3]; this.Refs = new Vp8LBackwardRefs[3];
this.HashChain = new Vp8LHashChain(pixelCount); 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: // We round the block size up, so we're guaranteed to have at most MaxRefsBlockPerImage blocks used:
int refsBlockSize = ((pixelCount - 1) / MaxRefsBlockPerImage) + 1; int refsBlockSize = ((pixelCount - 1) / MaxRefsBlockPerImage) + 1;
@ -230,13 +237,16 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
// Convert image pixels to bgra array. // Convert image pixels to bgra array.
Span<uint> bgra = this.Bgra.GetSpan(); Span<uint> bgra = this.Bgra.GetSpan();
using IMemoryOwner<Bgra32> bgraRowBuffer = this.memoryAllocator.Allocate<Bgra32>(width);
Span<Bgra32> bgraRow = bgraRowBuffer.GetSpan();
int idx = 0; int idx = 0;
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
Span<TPixel> rowSpan = image.GetPixelRowSpan(y); Span<TPixel> rowSpan = image.GetPixelRowSpan(y);
for (int x = 0; x < rowSpan.Length; x++) PixelOperations<TPixel>.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<uint> histoBuffer = this.memoryAllocator.Allocate<uint>((int)HistoIx.HistoTotal * 256); using IMemoryOwner<uint> histoBuffer = this.memoryAllocator.Allocate<uint>((int)HistoIx.HistoTotal * 256);
using IMemoryOwner<Bgra32> bgraBuffer = this.memoryAllocator.Allocate<Bgra32>(width);
Span<Bgra32> currentRow = bgraBuffer.GetSpan();
Span<uint> histo = histoBuffer.Memory.Span; Span<uint> histo = histoBuffer.Memory.Span;
Bgra32 pixPrev = ToBgra32(image.GetPixelRowSpan(0)[0]); // Skip the first pixel. TPixel firstPixel = image.GetPixelRowSpan(0)[0];
Span<TPixel> prevRow = null; Bgra32 bgra = default;
Rgba32 rgba = default;
firstPixel.ToRgba32(ref rgba);
bgra.FromRgba32(rgba);
Bgra32 pixPrev = bgra; // Skip the first pixel.
Span<Bgra32> prevRow = null;
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
Span<TPixel> currentRow = image.GetPixelRowSpan(y); Span<TPixel> pixelRow = image.GetPixelRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgra32(this.configuration, pixelRow, currentRow);
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
Bgra32 pix = ToBgra32(currentRow[x]); Bgra32 pix = currentRow[x];
uint pixDiff = LosslessUtils.SubPixels(pix.PackedValue, pixPrev.PackedValue); uint pixDiff = LosslessUtils.SubPixels(pix.PackedValue, pixPrev.PackedValue);
pixPrev = pix; pixPrev = pix;
if ((pixDiff == 0) || (prevRow != null && pix == ToBgra32(prevRow[x]))) if ((pixDiff == 0) || (prevRow != null && pix == prevRow[x]))
{ {
continue; continue;
} }
@ -1110,13 +1128,17 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
private int GetColorPalette<TPixel>(Image<TPixel> image, Span<uint> palette) private int GetColorPalette<TPixel>(Image<TPixel> image, Span<uint> palette)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
var colors = new HashSet<TPixel>(); int width = image.Width;
var colors = new HashSet<Bgra32>();
using IMemoryOwner<Bgra32> bgraRowBuffer = this.memoryAllocator.Allocate<Bgra32>(width);
Span<Bgra32> bgraRow = bgraRowBuffer.GetSpan();
for (int y = 0; y < image.Height; y++) for (int y = 0; y < image.Height; y++)
{ {
Span<TPixel> rowSpan = image.GetPixelRowSpan(y); Span<TPixel> rowSpan = image.GetPixelRowSpan(y);
for (int x = 0; x < rowSpan.Length; x++) PixelOperations<TPixel>.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) if (colors.Count > WebpConstants.MaxPaletteSize)
{ {
// Exact count is not needed, because a palette will not be used then anyway. // 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. // Fill the colors into the palette.
using HashSet<TPixel>.Enumerator colorEnumerator = colors.GetEnumerator(); using HashSet<Bgra32>.Enumerator colorEnumerator = colors.GetEnumerator();
int idx = 0; int idx = 0;
while (colorEnumerator.MoveNext()) while (colorEnumerator.MoveNext())
{ {
Bgra32 bgra = ToBgra32(colorEnumerator.Current); palette[idx++] = colorEnumerator.Current.PackedValue;
palette[idx++] = bgra.PackedValue;
} }
return colors.Count; return colors.Count;
@ -1591,16 +1612,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
return res; return res;
} }
[MethodImpl(InliningOptions.ShortMethod)]
private static Bgra32 ToBgra32<TPixel>(TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
Rgba32 rgba = default;
color.ToRgba32(ref rgba);
var bgra = new Bgra32(rgba.R, rgba.G, rgba.B, rgba.A);
return bgra;
}
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private static void AddSingle(uint p, Span<uint> a, Span<uint> r, Span<uint> g, Span<uint> b) private static void AddSingle(uint p, Span<uint> a, Span<uint> r, Span<uint> g, Span<uint> b)
{ {

2
src/ImageSharp/Formats/WebP/WebpEncoderCore.cs

@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
} }
else 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); enc.Encode(image, stream);
} }
} }

Loading…
Cancel
Save