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 countMask = pixelsPerByte - 1;
int bitMask = (1 << bitsPerPixel) - 1; int bitMask = (1 << bitsPerPixel) - 1;
// TODO: use memoryAllocator here
var decodedPixelData = new uint[width * height]; var decodedPixelData = new uint[width * height];
int pixelDataPos = 0; int pixelDataPos = 0;
for (int y = 0; y < height; ++y) for (int y = 0; y < height; ++y)
@ -167,11 +166,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
return newColorMap; 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 processedPixels = 0;
int yStart = 0; int yStart = 0;
int width = transform.XSize; 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; int endIdx = startIdx + numberOfPixels;
for (int x = startIdx; x < endIdx; ++x) 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; int endIdx = startIdx + numberOfPixels;
uint left = output[startIdx - 1]; 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 endIdx = startIdx + numberOfPixels;
int offset = 0; 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 endIdx = startIdx + numberOfPixels;
int offset = 0; 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 endIdx = startIdx + numberOfPixels;
int offset = 0; 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 endIdx = startIdx + numberOfPixels;
int offset = 0; 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 endIdx = startIdx + numberOfPixels;
int offset = 0; 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 endIdx = startIdx + numberOfPixels;
int offset = 0; 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 endIdx = startIdx + numberOfPixels;
int offset = 0; 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 endIdx = startIdx + numberOfPixels;
int offset = 0; 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 endIdx = startIdx + numberOfPixels;
int offset = 0; 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 endIdx = startIdx + numberOfPixels;
int offset = 0; 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 endIdx = startIdx + numberOfPixels;
int offset = 0; 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 endIdx = startIdx + numberOfPixels;
int offset = 0; int offset = 0;
@ -425,75 +421,75 @@ namespace SixLabors.ImageSharp.Formats.WebP
return WebPConstants.ArgbBlack; return WebPConstants.ArgbBlack;
} }
private static uint Predictor1(uint left, uint[] top) private static uint Predictor1(uint left, Span<uint> top)
{ {
return left; 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]; 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]; 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]; 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]); uint pred = Average3(left, top[idx], top[idx + 1]);
return pred; 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]); uint pred = Average2(left, top[idx - 1]);
return pred; 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]); uint pred = Average2(left, top[idx]);
return pred; 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]); uint pred = Average2(top[idx - 1], top[idx]);
return pred; 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]); uint pred = Average2(top[idx], top[idx + 1]);
return pred; 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]); uint pred = Average4(left, top[idx - 1], top[idx], top[idx + 1]);
return pred; 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]); uint pred = Select(top[idx], left, top[idx - 1]);
return pred; 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]); uint pred = ClampedAddSubtractFull(left, top[idx], top[idx - 1]);
return pred; 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]); uint pred = ClampedAddSubtractHalf(left, top[idx], top[idx - 1]);
return pred; 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 ColorCache { get; set; }
public ColorCache SavedColorCache { get; set; }
public int HuffmanMask { get; set; } public int HuffmanMask { get; set; }
public int HuffmanSubSampleBits { 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(); Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
if (imageInfo.IsLossLess) if (imageInfo.IsLossLess)
{ {
var losslessDecoder = new WebPLosslessDecoder(imageInfo.Vp9LBitReader); var losslessDecoder = new WebPLosslessDecoder(imageInfo.Vp9LBitReader, this.memoryAllocator);
losslessDecoder.Decode(pixels, image.Width, image.Height); losslessDecoder.Decode(pixels, image.Width, image.Height);
} }
else else
@ -256,6 +256,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
return new WebPImageInfo(); 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) private WebPImageInfo ReadVp8Header(WebPFeatures features = null)
{ {
this.webpMetadata.Format = WebPFormatType.Lossy; 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) private WebPImageInfo ReadVp8LHeader(WebPFeatures features = null)
{ {
this.webpMetadata.Format = WebPFormatType.Lossless; this.webpMetadata.Format = WebPFormatType.Lossless;
@ -319,7 +329,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
uint width = bitReader.ReadBits(WebPConstants.Vp8LImageSizeBits) + 1; uint width = bitReader.ReadBits(WebPConstants.Vp8LImageSizeBits) + 1;
uint height = 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(); 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. // 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> /// </summary>
public uint ImageDataSize { get; set; } 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. /// <summary>
public Vp8LBitReader Vp9LBitReader { get; set; } /// 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. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.WebP namespace SixLabors.ImageSharp.Formats.WebP
{ {
@ -70,13 +72,20 @@ 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>
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.bitReader = bitReader;
this.memoryAllocator = memoryAllocator;
} }
/// <summary> /// <summary>
@ -197,6 +206,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
int colorCacheLimit = lenCodeLimit + colorCacheSize; int colorCacheLimit = lenCodeLimit + colorCacheSize;
int mask = decoder.Metadata.HuffmanMask; int mask = decoder.Metadata.HuffmanMask;
HTreeGroup[] hTreeGroup = this.GetHTreeGroupForPos(decoder.Metadata, col, row); HTreeGroup[] hTreeGroup = this.GetHTreeGroupForPos(decoder.Metadata, col, row);
// TODO: use memory allocator
var pixelData = new uint[width * height]; var pixelData = new uint[width * height];
int totalPixels = width * height; int totalPixels = width * height;
@ -412,7 +422,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
alphabetSize += 1 << colorCacheBits; alphabetSize += 1 << colorCacheBits;
} }
int size = this.ReadHuffmanCode(decoder, alphabetSize, codeLengths, huffmanTable); int size = this.ReadHuffmanCode(alphabetSize, codeLengths, huffmanTable);
if (size is 0) if (size is 0)
{ {
WebPThrowHelper.ThrowImageFormatException("Huffman table size is zero"); WebPThrowHelper.ThrowImageFormatException("Huffman table size is zero");
@ -472,7 +482,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
decoder.Metadata.HuffmanTables = huffmanTables; 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(); bool simpleCode = this.bitReader.ReadBit();
for (int i = 0; i < alphabetSize; i++) for (int i = 0; i < alphabetSize; i++)
@ -491,7 +501,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
uint firstSymbolLenCode = this.bitReader.ReadBits(1); uint firstSymbolLenCode = this.bitReader.ReadBits(1);
// The first code is either 1 bit or 8 bit code. // 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; codeLengths[symbol] = 1;
// The second code (if present), is always 8 bit long. // 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); 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); int size = HuffmanUtils.BuildHuffmanTable(table, HuffmanUtils.HuffmanTableBits, codeLengths, alphabetSize);
@ -526,7 +536,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
return size; 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 maxSymbol;
int symbol = 0; int symbol = 0;
@ -580,13 +590,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
// TODO: not sure, if this should be treated as an error here // TODO: not sure, if this should be treated as an error here
return; return;
} }
else
int length = usePrev ? prevCodeLen : 0;
while (repeat-- > 0)
{ {
int length = usePrev ? prevCodeLen : 0; codeLengths[symbol++] = length;
while (repeat-- > 0)
{
codeLengths[symbol++] = length;
}
} }
} }
} }
@ -651,7 +659,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
switch (transformType) switch (transformType)
{ {
case Vp8LTransformType.PredictorTransform: 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; break;
case Vp8LTransformType.SubtractGreen: case Vp8LTransformType.SubtractGreen:
LosslessUtils.AddGreenToBlueAndRed(pixelData); LosslessUtils.AddGreenToBlueAndRed(pixelData);

Loading…
Cancel
Save