Browse Source

Use bulk pixel conversion

pull/1552/head
Brian Popow 6 years ago
parent
commit
fd92556fe0
  1. 5
      src/ImageSharp/Formats/WebP/AlphaDecoder.cs
  2. 4
      src/ImageSharp/Formats/WebP/WebPDecoderCore.cs
  3. 41
      src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs
  4. 63
      src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs

5
src/ImageSharp/Formats/WebP/AlphaDecoder.cs

@ -22,7 +22,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// <param name="data">The (maybe compressed) alpha data.</param>
/// <param name="alphaChunkHeader">The first byte of the alpha image stream contains information on ow to decode the stream.</param>
/// <param name="memoryAllocator">Used for allocating memory during decoding.</param>
public AlphaDecoder(int width, int height, byte[] data, byte alphaChunkHeader, MemoryAllocator memoryAllocator)
/// <param name="configuration">The configuration.</param>
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);
}
}

4
src/ImageSharp/Formats/WebP/WebPDecoderCore.cs

@ -89,12 +89,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
Buffer2D<TPixel> 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);
}

41
src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs

@ -27,6 +27,16 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
private readonly Vp8LBitReader bitReader;
/// <summary>
/// The global configuration.
/// </summary>
private readonly Configuration configuration;
/// <summary>
/// Used for allocating memory during processing operations.
/// </summary>
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
};
/// <summary>
/// Used for allocating memory during processing operations.
/// </summary>
private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// Initializes a new instance of the <see cref="WebPLosslessDecoder"/> class.
/// </summary>
/// <param name="bitReader">Bitreader to read from the stream.</param>
/// <param name="memoryAllocator">Used for allocating memory during processing operations.</param>
public WebPLosslessDecoder(Vp8LBitReader bitReader, MemoryAllocator memoryAllocator)
/// <param name="configuration">The configuration.</param>
public WebPLosslessDecoder(Vp8LBitReader bitReader, MemoryAllocator memoryAllocator, Configuration configuration)
{
this.bitReader = bitReader;
this.memoryAllocator = memoryAllocator;
this.configuration = configuration;
}
/// <summary>
@ -181,25 +188,21 @@ namespace SixLabors.ImageSharp.Formats.WebP
where TPixel : struct, IPixel<TPixel>
{
Span<uint> pixelData = decoder.Pixels.GetSpan();
int width = decoder.Width;
// Apply reverse transformations, if any are present.
this.ApplyInverseTransforms(decoder, pixelData);
TPixel color = default;
Span<byte> pixelDataAsBytes = MemoryMarshal.Cast<uint, byte>(pixelData);
for (int y = 0; y < decoder.Height; y++)
{
Span<TPixel> 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<byte> row = pixelDataAsBytes.Slice(y * width * 4, width * 4);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.FromBgra32Bytes(
this.configuration,
row,
pixelSpan,
width);
}
}

63
src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs

@ -24,15 +24,22 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// The global configuration.
/// </summary>
private readonly Configuration configuration;
/// <summary>
/// Initializes a new instance of the <see cref="WebPLossyDecoder"/> class.
/// </summary>
/// <param name="bitReader">Bitreader to read from the stream.</param>
/// <param name="memoryAllocator">Used for allocating memory during processing operations.</param>
public WebPLossyDecoder(Vp8BitReader bitReader, MemoryAllocator memoryAllocator)
/// <param name="configuration">The configuration.</param>
public WebPLossyDecoder(Vp8BitReader bitReader, MemoryAllocator memoryAllocator, Configuration configuration)
{
this.memoryAllocator = memoryAllocator;
this.bitReader = bitReader;
this.memoryAllocator = memoryAllocator;
this.configuration = configuration;
}
public void Decode<TPixel>(Buffer2D<TPixel> 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<TPixel>(int width, int height, Span<byte> pixelData, Buffer2D<TPixel> pixels, IMemoryOwner<byte> alpha = null)
where TPixel : struct, IPixel<TPixel>
{
TPixel color = default;
bool hasAlpha = false;
Span<byte> alphaSpan = null;
if (alpha != null)
{
hasAlpha = true;
alphaSpan = alpha.Memory.Span;
}
for (int y = 0; y < height; y++)
{
Span<TPixel> pixelRow = pixels.GetRowSpan(y);
for (int x = 0; x < width; x++)
TPixel color = default;
Span<byte> 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<TPixel> 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<byte> row = pixelData.Slice(y * width * 3, width * 3);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.FromBgr24Bytes(
this.configuration,
row,
pixelSpan,
width);
}
}

Loading…
Cancel
Save