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="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="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> /// <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.Width = width;
this.Height = height; this.Height = height;
@ -59,7 +60,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
if (this.Compressed) if (this.Compressed)
{ {
var bitReader = new Vp8LBitReader(data); 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); 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(); Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
if (imageInfo.IsLossLess) 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); losslessDecoder.Decode(pixels, image.Width, image.Height);
} }
else 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); 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> /// </summary>
private readonly Vp8LBitReader bitReader; 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 BitsSpecialMarker = 0x100;
private static readonly int NumArgbCacheRows = 16; private static readonly int NumArgbCacheRows = 16;
@ -62,20 +72,17 @@ namespace SixLabors.ImageSharp.Formats.WebP
0, 1, 1, 1, 0 0, 1, 1, 1, 0
}; };
/// <summary>
/// Used for allocating memory during processing operations.
/// </summary>
private readonly MemoryAllocator memoryAllocator;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WebPLosslessDecoder"/> class. /// Initializes a new instance of the <see cref="WebPLosslessDecoder"/> class.
/// </summary> /// </summary>
/// <param name="bitReader">Bitreader to read from the stream.</param> /// <param name="bitReader">Bitreader to read from the stream.</param>
/// <param name="memoryAllocator">Used for allocating memory during processing operations.</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.bitReader = bitReader;
this.memoryAllocator = memoryAllocator; this.memoryAllocator = memoryAllocator;
this.configuration = configuration;
} }
/// <summary> /// <summary>
@ -181,25 +188,21 @@ namespace SixLabors.ImageSharp.Formats.WebP
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
Span<uint> pixelData = decoder.Pixels.GetSpan(); Span<uint> pixelData = decoder.Pixels.GetSpan();
int width = decoder.Width;
// Apply reverse transformations, if any are present. // Apply reverse transformations, if any are present.
this.ApplyInverseTransforms(decoder, pixelData); this.ApplyInverseTransforms(decoder, pixelData);
TPixel color = default; Span<byte> pixelDataAsBytes = MemoryMarshal.Cast<uint, byte>(pixelData);
for (int y = 0; y < decoder.Height; y++) for (int y = 0; y < decoder.Height; y++)
{ {
Span<TPixel> pixelRow = pixels.GetRowSpan(y); Span<byte> row = pixelDataAsBytes.Slice(y * width * 4, width * 4);
for (int x = 0; x < decoder.Width; x++) Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
{ PixelOperations<TPixel>.Instance.FromBgra32Bytes(
int idx = (y * decoder.Width) + x; this.configuration,
uint pixel = pixelData[idx]; row,
byte a = (byte)((pixel & 0xFF000000) >> 24); pixelSpan,
byte r = (byte)((pixel & 0xFF0000) >> 16); width);
byte g = (byte)((pixel & 0xFF00) >> 8);
byte b = (byte)(pixel & 0xFF);
color.FromRgba32(new Rgba32(r, g, b, a));
pixelRow[x] = color;
}
} }
} }

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

@ -24,15 +24,22 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary> /// </summary>
private readonly MemoryAllocator memoryAllocator; private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// The global configuration.
/// </summary>
private readonly Configuration configuration;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WebPLossyDecoder"/> class. /// Initializes a new instance of the <see cref="WebPLossyDecoder"/> class.
/// </summary> /// </summary>
/// <param name="bitReader">Bitreader to read from the stream.</param> /// <param name="bitReader">Bitreader to read from the stream.</param>
/// <param name="memoryAllocator">Used for allocating memory during processing operations.</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.bitReader = bitReader;
this.memoryAllocator = memoryAllocator;
this.configuration = configuration;
} }
public void Decode<TPixel>(Buffer2D<TPixel> pixels, int width, int height, WebPImageInfo info) public void Decode<TPixel>(Buffer2D<TPixel> pixels, int width, int height, WebPImageInfo info)
@ -85,7 +92,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
height, height,
info.Features.AlphaData, info.Features.AlphaData,
info.Features.AlphaChunkHeader, info.Features.AlphaChunkHeader,
this.memoryAllocator)) this.memoryAllocator,
this.configuration))
{ {
alphaDecoder.Decode(); alphaDecoder.Decode();
this.DecodePixelValues(width, height, decoder.Pixels.Memory.Span, pixels, alphaDecoder.Alpha); 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) private void DecodePixelValues<TPixel>(int width, int height, Span<byte> pixelData, Buffer2D<TPixel> pixels, IMemoryOwner<byte> alpha = null)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel color = default;
bool hasAlpha = false;
Span<byte> alphaSpan = null;
if (alpha != null) if (alpha != null)
{ {
hasAlpha = true; TPixel color = default;
alphaSpan = alpha.Memory.Span; Span<byte> alphaSpan = alpha.Memory.Span;
} for (int y = 0; y < height; y++)
for (int y = 0; y < height; y++)
{
Span<TPixel> pixelRow = pixels.GetRowSpan(y);
for (int x = 0; x < width; x++)
{ {
int offset = (y * width) + x; Span<TPixel> pixelRow = pixels.GetRowSpan(y);
int idxBgr = offset * 3; for (int x = 0; x < width; x++)
byte b = pixelData[idxBgr];
byte g = pixelData[idxBgr + 1];
byte r = pixelData[idxBgr + 2];
// TODO: use bulk conversion here.
if (hasAlpha)
{ {
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]; byte a = alphaSpan[offset];
color.FromBgra32(new Bgra32(r, g, b, a)); 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