Browse Source

Add ReadHuffmanCodeLengths

pull/1147/head
Brian Popow 7 years ago
parent
commit
d525f662b5
  1. 12
      src/ImageSharp/Formats/WebP/WebPConstants.cs
  2. 97
      src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs

12
src/ImageSharp/Formats/WebP/WebPConstants.cs

@ -76,6 +76,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
public static int MaxAllowedCodeLength = 15;
public static int DefaultCodeLength = 8;
public static int HuffmanCodesPerMetaCode = 5;
public static int NumLiteralCodes = 256;
@ -86,6 +88,16 @@ namespace SixLabors.ImageSharp.Formats.WebP
public static int NumCodeLengthCodes = 19;
public static int LengthTableBits = 7;
public static int kCodeLengthLiterals = 16;
public static int kCodeLengthRepeatCode = 16;
public static int[] kCodeLengthExtraBits = { 2, 3, 7 };
public static int[] kCodeLengthRepeatOffsets = { 3, 3, 11 };
public static byte[] KCodeLengthCodeOrder = { 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
public static int[] kAlphabetSize = {

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

@ -101,10 +101,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
alphabetSize += 1 << colorCacheBits;
size = this.ReadHuffmanCode(alphabetSize, codeLengths);
if (size is 0)
/*if (size is 0)
{
WebPThrowHelper.ThrowImageFormatException("Huffman table size is zero");
}
}*/
}
}
}
@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
codeLengthCodeLengths[WebPConstants.KCodeLengthCodeOrder[i]] = (int)this.bitReader.Read(3);
}
// TODO: ReadHuffmanCodeLengths
this.ReadHuffmanCodeLengths(codeLengthCodeLengths, alphabetSize, codeLengths);
}
int size = 0;
@ -160,9 +160,66 @@ namespace SixLabors.ImageSharp.Formats.WebP
return size;
}
private int BuildHuffmanTable(int rootBits, int[] codeLengths, int codeLengthsSize,
int[] sorted) // sorted[code_lengths_size] is a pre-allocated array for sorting symbols by code length.
private void ReadHuffmanCodeLengths(int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths)
{
int maxSymbol;
int symbol = 0;
int prevCodeLen = WebPConstants.DefaultCodeLength;
BuildHuffmanTable(WebPConstants.LengthTableBits, codeLengthCodeLengths, WebPConstants.NumCodeLengthCodes);
if (this.bitReader.ReadBit())
{
int lengthNBits = 2 + (2 * (int)this.bitReader.Read(3));
maxSymbol = 2 + (int)this.bitReader.Read(lengthNBits);
}
else
{
maxSymbol = numSymbols;
}
while (symbol < numSymbols)
{
int codeLen;
if (maxSymbol-- == 0)
{
break;
}
codeLen = int.MaxValue; // TODO: this is wrong
if (codeLen < WebPConstants.kCodeLengthLiterals)
{
codeLengths[symbol++] = codeLen;
if (codeLen != 0)
{
prevCodeLen = codeLen;
}
}
else
{
bool usePrev = codeLen == WebPConstants.kCodeLengthRepeatCode;
int slot = codeLen - WebPConstants.kCodeLengthLiterals;
int extraBits = WebPConstants.kCodeLengthExtraBits[slot];
int repeatOffset = WebPConstants.kCodeLengthRepeatOffsets[slot];
int repeat = (int)(this.bitReader.Read(extraBits) + repeatOffset);
if (symbol + repeat > numSymbols)
{
return;
}
else
{
int length = usePrev ? prevCodeLen : 0;
while (repeat-- > 0)
{
codeLengths[symbol++] = length;
}
}
}
}
}
private int BuildHuffmanTable(int rootBits, int[] codeLengths, int codeLengthsSize)
{
// sorted[code_lengths_size] is a pre-allocated array for sorting symbols by code length.
var sorted = new int[codeLengthsSize];
// total size root table + 2nd level table
int totalSize = 1 << rootBits;
// current code length
@ -219,6 +276,36 @@ namespace SixLabors.ImageSharp.Formats.WebP
return totalSize;
}
int step; // step size to replicate values in current table
int low = -1; // low bits for current root entry
int mask = totalSize - 1; // mask for low bits
int key = 0; // reversed prefix code
int numNodes = 1; // number of Huffman tree nodes
int numOpen = 1; // number of open branches in current tree level
int tableBits = rootBits; // key length of current table
int tableSize = 1 << tableBits; // size of current table
symbol = 0;
// Fill in root table.
for (len = 1, step = 2; len <= rootBits; ++len, step <<= 1)
{
numOpen <<= 1;
numNodes += numOpen;
numOpen -= count[len];
if (numOpen < 0)
{
return 0;
}
for (; count[len] > 0; --count[len])
{
var code = new HuffmanCode()
{
BitsUsed = len,
Value = sorted[symbol++]
};
}
}
return 0;
}

Loading…
Cancel
Save