Browse Source

Use memory allocator

pull/1552/head
Brian Popow 6 years ago
parent
commit
864aaa52a2
  1. 62
      src/ImageSharp/Formats/WebP/LosslessUtils.cs
  2. 2
      src/ImageSharp/Formats/WebP/Vp8LMetadata.cs
  3. 14
      src/ImageSharp/Formats/WebP/WebPDecoderCore.cs
  4. 6
      src/ImageSharp/Formats/WebP/WebPImageInfo.cs
  5. 38
      src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs

62
src/ImageSharp/Formats/WebP/LosslessUtils.cs

@ -41,7 +41,6 @@ namespace SixLabors.ImageSharp.Formats.WebP
int countMask = pixelsPerByte - 1;
int bitMask = (1 << bitsPerPixel) - 1;
// TODO: use memoryAllocator here
var decodedPixelData = new uint[width * height];
int pixelDataPos = 0;
for (int y = 0; y < height; ++y)
@ -167,11 +166,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
return newColorMap;
}
public static void PredictorInverseTransform(Vp8LTransform transform, uint[] pixelData)
public static void PredictorInverseTransform(Vp8LTransform transform, uint[] pixelData, Span<uint> output)
{
// TODO: use memory allocator instead
var output = new uint[pixelData.Length];
int processedPixels = 0;
int yStart = 0;
int width = transform.XSize;
@ -265,10 +261,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
output.AsSpan().CopyTo(pixelData);
output.CopyTo(pixelData);
}
private static void PredictorAdd0(uint[] input, int startIdx, int numberOfPixels, uint[] output)
private static void PredictorAdd0(Span<uint> input, int startIdx, int numberOfPixels, Span<uint> output)
{
int endIdx = startIdx + numberOfPixels;
for (int x = startIdx; x < endIdx; ++x)
@ -278,7 +274,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private static void PredictorAdd1(uint[] input, int startIdx, int numberOfPixels, uint[] output)
private static void PredictorAdd1(Span<uint> input, int startIdx, int numberOfPixels, Span<uint> output)
{
int endIdx = startIdx + numberOfPixels;
uint left = output[startIdx - 1];
@ -288,7 +284,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private static void PredictorAdd2(uint[] input, int startIdx, int numberOfPixels, int width, uint[] output)
private static void PredictorAdd2(Span<uint> input, int startIdx, int numberOfPixels, int width, Span<uint> output)
{
int endIdx = startIdx + numberOfPixels;
int offset = 0;
@ -299,7 +295,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private static void PredictorAdd3(uint[] input, int startIdx, int numberOfPixels, int width, uint[] output)
private static void PredictorAdd3(Span<uint> input, int startIdx, int numberOfPixels, int width, Span<uint> output)
{
int endIdx = startIdx + numberOfPixels;
int offset = 0;
@ -310,7 +306,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private static void PredictorAdd4(uint[] input, int startIdx, int numberOfPixels, int width, uint[] output)
private static void PredictorAdd4(Span<uint> input, int startIdx, int numberOfPixels, int width, Span<uint> output)
{
int endIdx = startIdx + numberOfPixels;
int offset = 0;
@ -321,7 +317,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private static void PredictorAdd5(uint[] input, int startIdx, int numberOfPixels, int width, uint[] output)
private static void PredictorAdd5(Span<uint> input, int startIdx, int numberOfPixels, int width, Span<uint> output)
{
int endIdx = startIdx + numberOfPixels;
int offset = 0;
@ -332,7 +328,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private static void PredictorAdd6(uint[] input, int startIdx, int numberOfPixels, int width, uint[] output)
private static void PredictorAdd6(Span<uint> input, int startIdx, int numberOfPixels, int width, Span<uint> output)
{
int endIdx = startIdx + numberOfPixels;
int offset = 0;
@ -343,7 +339,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private static void PredictorAdd7(uint[] input, int startIdx, int numberOfPixels, int width, uint[] output)
private static void PredictorAdd7(Span<uint> input, int startIdx, int numberOfPixels, int width, Span<uint> output)
{
int endIdx = startIdx + numberOfPixels;
int offset = 0;
@ -354,7 +350,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private static void PredictorAdd8(uint[] input, int startIdx, int numberOfPixels, int width, uint[] output)
private static void PredictorAdd8(Span<uint> input, int startIdx, int numberOfPixels, int width, Span<uint> output)
{
int endIdx = startIdx + numberOfPixels;
int offset = 0;
@ -365,7 +361,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private static void PredictorAdd9(uint[] input, int startIdx, int numberOfPixels, int width, uint[] output)
private static void PredictorAdd9(Span<uint> input, int startIdx, int numberOfPixels, int width, Span<uint> output)
{
int endIdx = startIdx + numberOfPixels;
int offset = 0;
@ -376,7 +372,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private static void PredictorAdd10(uint[] input, int startIdx, int numberOfPixels, int width, uint[] output)
private static void PredictorAdd10(Span<uint> input, int startIdx, int numberOfPixels, int width, Span<uint> output)
{
int endIdx = startIdx + numberOfPixels;
int offset = 0;
@ -387,7 +383,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private static void PredictorAdd11(uint[] input, int startIdx, int numberOfPixels, int width, uint[] output)
private static void PredictorAdd11(Span<uint> input, int startIdx, int numberOfPixels, int width, Span<uint> output)
{
int endIdx = startIdx + numberOfPixels;
int offset = 0;
@ -398,7 +394,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private static void PredictorAdd12(uint[] input, int startIdx, int numberOfPixels, int width, uint[] output)
private static void PredictorAdd12(Span<uint> input, int startIdx, int numberOfPixels, int width, Span<uint> output)
{
int endIdx = startIdx + numberOfPixels;
int offset = 0;
@ -409,7 +405,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
private static void PredictorAdd13(uint[] input, int startIdx, int numberOfPixels, int width, uint[] output)
private static void PredictorAdd13(Span<uint> input, int startIdx, int numberOfPixels, int width, Span<uint> output)
{
int endIdx = startIdx + numberOfPixels;
int offset = 0;
@ -425,75 +421,75 @@ namespace SixLabors.ImageSharp.Formats.WebP
return WebPConstants.ArgbBlack;
}
private static uint Predictor1(uint left, uint[] top)
private static uint Predictor1(uint left, Span<uint> top)
{
return left;
}
private static uint Predictor2(uint left, uint[] top, int idx)
private static uint Predictor2(uint left, Span<uint> top, int idx)
{
return top[idx];
}
private static uint Predictor3(uint left, uint[] top, int idx)
private static uint Predictor3(uint left, Span<uint> top, int idx)
{
return top[idx + 1];
}
private static uint Predictor4(uint left, uint[] top, int idx)
private static uint Predictor4(uint left, Span<uint> top, int idx)
{
return top[idx - 1];
}
private static uint Predictor5(uint left, uint[] top, int idx)
private static uint Predictor5(uint left, Span<uint> top, int idx)
{
uint pred = Average3(left, top[idx], top[idx + 1]);
return pred;
}
private static uint Predictor6(uint left, uint[] top, int idx)
private static uint Predictor6(uint left, Span<uint> top, int idx)
{
uint pred = Average2(left, top[idx - 1]);
return pred;
}
private static uint Predictor7(uint left, uint[] top, int idx)
private static uint Predictor7(uint left, Span<uint> top, int idx)
{
uint pred = Average2(left, top[idx]);
return pred;
}
private static uint Predictor8(uint left, uint[] top, int idx)
private static uint Predictor8(uint left, Span<uint> top, int idx)
{
uint pred = Average2(top[idx - 1], top[idx]);
return pred;
}
private static uint Predictor9(uint left, uint[] top, int idx)
private static uint Predictor9(uint left, Span<uint> top, int idx)
{
uint pred = Average2(top[idx], top[idx + 1]);
return pred;
}
private static uint Predictor10(uint left, uint[] top, int idx)
private static uint Predictor10(uint left, Span<uint> top, int idx)
{
uint pred = Average4(left, top[idx - 1], top[idx], top[idx + 1]);
return pred;
}
private static uint Predictor11(uint left, uint[] top, int idx)
private static uint Predictor11(uint left, Span<uint> top, int idx)
{
uint pred = Select(top[idx], left, top[idx - 1]);
return pred;
}
private static uint Predictor12(uint left, uint[] top, int idx)
private static uint Predictor12(uint left, Span<uint> top, int idx)
{
uint pred = ClampedAddSubtractFull(left, top[idx], top[idx - 1]);
return pred;
}
private static uint Predictor13(uint left, uint[] top, int idx)
private static uint Predictor13(uint left, Span<uint> top, int idx)
{
uint pred = ClampedAddSubtractHalf(left, top[idx], top[idx - 1]);
return pred;

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

@ -9,8 +9,6 @@ namespace SixLabors.ImageSharp.Formats.WebP
public ColorCache ColorCache { get; set; }
public ColorCache SavedColorCache { get; set; }
public int HuffmanMask { get; set; }
public int HuffmanSubSampleBits { get; set; }

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

@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
if (imageInfo.IsLossLess)
{
var losslessDecoder = new WebPLosslessDecoder(imageInfo.Vp9LBitReader);
var losslessDecoder = new WebPLosslessDecoder(imageInfo.Vp9LBitReader, this.memoryAllocator);
losslessDecoder.Decode(pixels, image.Width, image.Height);
}
else
@ -256,6 +256,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
return new WebPImageInfo();
}
/// <summary>
/// Reads the header of a lossy webp image.
/// </summary>
/// <param name="features">Webp features.</param>
/// <returns>Information about this webp image.</returns>
private WebPImageInfo ReadVp8Header(WebPFeatures features = null)
{
this.webpMetadata.Format = WebPFormatType.Lossy;
@ -300,6 +305,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
};
}
/// <summary>
/// Reads the header of lossless webp image.
/// </summary>
/// <param name="features">Webp image features.</param>
/// <returns>Information about this image.</returns>
private WebPImageInfo ReadVp8LHeader(WebPFeatures features = null)
{
this.webpMetadata.Format = WebPFormatType.Lossless;
@ -319,7 +329,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
uint width = bitReader.ReadBits(WebPConstants.Vp8LImageSizeBits) + 1;
uint height = bitReader.ReadBits(WebPConstants.Vp8LImageSizeBits) + 1;
// The alpha_is_used flag should be set to 0 when all alpha values are 255 in the picture, and 1 otherwise.
// The alphaIsUsed flag should be set to 0 when all alpha values are 255 in the picture, and 1 otherwise.
bool alphaIsUsed = bitReader.ReadBit();
// The next 3 bits are the version. The version_number is a 3 bit code that must be set to 0.

6
src/ImageSharp/Formats/WebP/WebPImageInfo.cs

@ -30,7 +30,9 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
public uint ImageDataSize { get; set; }
// TODO: not sure if the bitreader is in the right place here, but for the sake of simplicity it will stay here for now. Will be refactored later.
public Vp8LBitReader Vp9LBitReader { get; set; }
/// <summary>
/// Gets or sets Vp8L bitreader. Will be null if its not lossless image.
/// </summary>
public Vp8LBitReader Vp9LBitReader { get; set; } = null;
}
}

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

@ -2,11 +2,13 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.WebP
{
@ -70,13 +72,20 @@ 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>
public WebPLosslessDecoder(Vp8LBitReader bitReader)
/// <param name="memoryAllocator">Used for allocating memory during processing operations.</param>
public WebPLosslessDecoder(Vp8LBitReader bitReader, MemoryAllocator memoryAllocator)
{
this.bitReader = bitReader;
this.memoryAllocator = memoryAllocator;
}
/// <summary>
@ -197,6 +206,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
int colorCacheLimit = lenCodeLimit + colorCacheSize;
int mask = decoder.Metadata.HuffmanMask;
HTreeGroup[] hTreeGroup = this.GetHTreeGroupForPos(decoder.Metadata, col, row);
// TODO: use memory allocator
var pixelData = new uint[width * height];
int totalPixels = width * height;
@ -412,7 +422,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
alphabetSize += 1 << colorCacheBits;
}
int size = this.ReadHuffmanCode(decoder, alphabetSize, codeLengths, huffmanTable);
int size = this.ReadHuffmanCode(alphabetSize, codeLengths, huffmanTable);
if (size is 0)
{
WebPThrowHelper.ThrowImageFormatException("Huffman table size is zero");
@ -472,7 +482,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
decoder.Metadata.HuffmanTables = huffmanTables;
}
private int ReadHuffmanCode(Vp8LDecoder decoder, int alphabetSize, int[] codeLengths, Span<HuffmanCode> table)
private int ReadHuffmanCode(int alphabetSize, int[] codeLengths, Span<HuffmanCode> table)
{
bool simpleCode = this.bitReader.ReadBit();
for (int i = 0; i < alphabetSize; i++)
@ -491,7 +501,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
uint firstSymbolLenCode = this.bitReader.ReadBits(1);
// The first code is either 1 bit or 8 bit code.
uint symbol = this.bitReader.ReadBits((firstSymbolLenCode == 0) ? 1 : 8);
uint symbol = this.bitReader.ReadBits((firstSymbolLenCode is 0) ? 1 : 8);
codeLengths[symbol] = 1;
// The second code (if present), is always 8 bit long.
@ -518,7 +528,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
codeLengthCodeLengths[KCodeLengthCodeOrder[i]] = (int)this.bitReader.ReadBits(3);
}
this.ReadHuffmanCodeLengths(decoder, table.ToArray(), codeLengthCodeLengths, alphabetSize, codeLengths);
this.ReadHuffmanCodeLengths(table.ToArray(), codeLengthCodeLengths, alphabetSize, codeLengths);
}
int size = HuffmanUtils.BuildHuffmanTable(table, HuffmanUtils.HuffmanTableBits, codeLengths, alphabetSize);
@ -526,7 +536,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
return size;
}
private void ReadHuffmanCodeLengths(Vp8LDecoder decoder, HuffmanCode[] table, int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths)
private void ReadHuffmanCodeLengths(HuffmanCode[] table, int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths)
{
int maxSymbol;
int symbol = 0;
@ -580,13 +590,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
// TODO: not sure, if this should be treated as an error here
return;
}
else
int length = usePrev ? prevCodeLen : 0;
while (repeat-- > 0)
{
int length = usePrev ? prevCodeLen : 0;
while (repeat-- > 0)
{
codeLengths[symbol++] = length;
}
codeLengths[symbol++] = length;
}
}
}
@ -651,7 +659,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
switch (transformType)
{
case Vp8LTransformType.PredictorTransform:
LosslessUtils.PredictorInverseTransform(transforms[i], pixelData);
using (IMemoryOwner<uint> output = this.memoryAllocator.Allocate<uint>(pixelData.Length, AllocationOptions.Clean))
{
LosslessUtils.PredictorInverseTransform(transforms[i], pixelData, output.GetSpan());
}
break;
case Vp8LTransformType.SubtractGreen:
LosslessUtils.AddGreenToBlueAndRed(pixelData);

Loading…
Cancel
Save