Browse Source

Continue with ReadHuffmanCodes

pull/1552/head
Brian Popow 7 years ago
parent
commit
41eaff0cc2
  1. 9
      src/ImageSharp/Formats/WebP/HTreeGroup.cs
  2. 36
      src/ImageSharp/Formats/WebP/HuffIndex.cs
  3. 10
      src/ImageSharp/Formats/WebP/HuffmanUtils.cs
  4. 82
      src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs

9
src/ImageSharp/Formats/WebP/HTreeGroup.cs

@ -16,10 +16,15 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary> /// </summary>
internal class HTreeGroup internal class HTreeGroup
{ {
public HTreeGroup()
{
HTree = new List<HuffmanCode[]>(WebPConstants.HuffmanCodesPerMetaCode);
}
/// <summary> /// <summary>
/// This has a maximum of HuffmanCodesPerMetaCode (5) entrys. /// This has a maximum of HuffmanCodesPerMetaCode (5) entrys.
/// </summary> /// </summary>
public List<HuffmanCode> HTree { get; set; } public List<HuffmanCode[]> HTree { get; private set; }
/// <summary> /// <summary>
/// True, if huffman trees for Red, Blue & Alpha Symbols are trivial (have a single code). /// True, if huffman trees for Red, Blue & Alpha Symbols are trivial (have a single code).
@ -29,7 +34,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// <summary> /// <summary>
/// If is_trivial_literal is true, this is the ARGB value of the pixel, with Green channel being set to zero. /// If is_trivial_literal is true, this is the ARGB value of the pixel, with Green channel being set to zero.
/// </summary> /// </summary>
public int LiteralArb { get; set; } public uint LiteralArb { get; set; }
/// <summary> /// <summary>
/// True if is_trivial_literal with only one code. /// True if is_trivial_literal with only one code.

36
src/ImageSharp/Formats/WebP/HuffIndex.cs

@ -0,0 +1,36 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.WebP
{
/// <summary>
/// Five Huffman codes are used at each meta code.
/// </summary>
public enum HuffIndex : int
{
/// <summary>
/// Green + length prefix codes + color cache codes.
/// </summary>
Green = 0,
/// <summary>
/// Red.
/// </summary>
Red = 1,
/// <summary>
/// Blue.
/// </summary>
Blue = 2,
/// <summary>
/// Alpha.
/// </summary>
Alpha = 3,
/// <summary>
/// Distance prefix codes.
/// </summary>
Dist = 4
}
}

10
src/ImageSharp/Formats/WebP/HuffmanUtils.cs

@ -9,9 +9,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
{ {
public const int HuffmanTableBits = 8; public const int HuffmanTableBits = 8;
public const int HuffmanPackedBits = 6;
public const int HuffmanTableMask = (1 << HuffmanTableBits) - 1; public const int HuffmanTableMask = (1 << HuffmanTableBits) - 1;
public static int BuildHuffmanTable(HuffmanCode[] table, int rootBits, int[] codeLengths, int codeLengthsSize) public static int BuildHuffmanTable(Span<HuffmanCode> table, int rootBits, int[] codeLengths, int codeLengthsSize)
{ {
Guard.MustBeGreaterThan(rootBits, 0, nameof(rootBits)); Guard.MustBeGreaterThan(rootBits, 0, nameof(rootBits));
Guard.NotNull(codeLengths, nameof(codeLengths)); Guard.NotNull(codeLengths, nameof(codeLengths));
@ -38,7 +40,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
return 0; return 0;
} }
++count[codeLengths[symbol]]; count[codeLengths[symbol]]++;
} }
// Generate offsets into sorted symbol table by code length. // Generate offsets into sorted symbol table by code length.
@ -102,7 +104,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
BitsUsed = len, BitsUsed = len,
Value = sorted[symbol++] Value = sorted[symbol++]
}; };
ReplicateValue(table.AsSpan(key), step, tableSize, huffmanCode); ReplicateValue(table.Slice(key), step, tableSize, huffmanCode);
key = GetNextKey(key, len); key = GetNextKey(key, len);
} }
} }
@ -118,7 +120,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
return 0; return 0;
} }
Span<HuffmanCode> tableSpan = table.AsSpan(); Span<HuffmanCode> tableSpan = table;
for (; count[len] > 0; --count[len]) for (; count[len] > 0; --count[len])
{ {
if ((key & mask) != low) if ((key & mask) != low)

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

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -25,7 +26,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
private static int FIXED_TABLE_SIZE = 630 * 3 + 410; private static int FIXED_TABLE_SIZE = 630 * 3 + 410;
private static int[] kTableSize = private static readonly int[] kTableSize =
{ {
FIXED_TABLE_SIZE + 654, FIXED_TABLE_SIZE + 654,
FIXED_TABLE_SIZE + 656, FIXED_TABLE_SIZE + 656,
@ -41,6 +42,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
FIXED_TABLE_SIZE + 2704 FIXED_TABLE_SIZE + 2704
}; };
private static readonly byte[] kLiteralMap =
{
0, 1, 1, 1, 0
};
public WebPLosslessDecoder(Vp8LBitReader bitReader, int imageDataSize) public WebPLosslessDecoder(Vp8LBitReader bitReader, int imageDataSize)
{ {
this.bitReader = bitReader; this.bitReader = bitReader;
@ -108,12 +114,16 @@ namespace SixLabors.ImageSharp.Formats.WebP
} }
int tableSize = kTableSize[colorCacheBits]; int tableSize = kTableSize[colorCacheBits];
var table = new HuffmanCode[numHtreeGroups * tableSize]; var huffmanTables = new HuffmanCode[numHtreeGroups * tableSize];
var hTreeGroups = new HTreeGroup[numHtreeGroups];
Span<HuffmanCode> huffmanTable = huffmanTables.AsSpan();
for (int i = 0; i < numHtreeGroupsMax; i++) for (int i = 0; i < numHtreeGroupsMax; i++)
{ {
hTreeGroups[i] = new HTreeGroup();
HTreeGroup hTreeGroup = hTreeGroups[i];
int size; int size;
int totalSize = 0; int totalSize = 0;
int isTrivialLiteral = 1; bool isTrivialLiteral = true;
int maxBits = 0; int maxBits = 0;
var codeLengths = new int[maxAlphabetSize]; var codeLengths = new int[maxAlphabetSize];
for (int j = 0; j < WebPConstants.HuffmanCodesPerMetaCode; j++) for (int j = 0; j < WebPConstants.HuffmanCodesPerMetaCode; j++)
@ -121,24 +131,72 @@ namespace SixLabors.ImageSharp.Formats.WebP
int alphabetSize = WebPConstants.kAlphabetSize[j]; int alphabetSize = WebPConstants.kAlphabetSize[j];
if (j == 0 && colorCacheBits > 0) if (j == 0 && colorCacheBits > 0)
{ {
if (j == 0 && colorCacheBits > 0) alphabetSize += 1 << colorCacheBits;
{ }
alphabetSize += 1 << colorCacheBits;
} size = this.ReadHuffmanCode(alphabetSize, codeLengths, huffmanTable);
if (size is 0)
{
WebPThrowHelper.ThrowImageFormatException("Huffman table size is zero");
}
hTreeGroup.HTree.Add(huffmanTable.ToArray());
if (isTrivialLiteral && kLiteralMap[j] == 1)
{
isTrivialLiteral = huffmanTable[0].BitsUsed == 0;
}
totalSize += huffmanTable[0].BitsUsed;
huffmanTable = huffmanTable.Slice(size);
size = this.ReadHuffmanCode(alphabetSize, codeLengths, table); if (j <= (int)HuffIndex.Alpha)
if (size is 0) {
int localMaxBits = codeLengths[0];
int k;
for (k = 1; k < alphabetSize; ++k)
{ {
WebPThrowHelper.ThrowImageFormatException("Huffman table size is zero"); if (codeLengths[k] > localMaxBits)
{
localMaxBits = codeLengths[k];
}
} }
maxBits += localMaxBits;
}
}
hTreeGroup.IsTrivialLiteral = isTrivialLiteral;
hTreeGroup.IsTrivialCode = false;
if (isTrivialLiteral)
{
int red = hTreeGroup.HTree[(int)HuffIndex.Red].First().Value;
int blue = hTreeGroup.HTree[(int)HuffIndex.Blue].First().Value;
int green = hTreeGroup.HTree[(int)HuffIndex.Green].First().Value;
int alpha = hTreeGroup.HTree[(int)HuffIndex.Alpha].First().Value;
hTreeGroup.LiteralArb = (uint)((alpha << 24) | (red << 16) | blue);
if (totalSize == 0 && green < WebPConstants.NumLiteralCodes)
{
hTreeGroup.IsTrivialCode = true;
hTreeGroup.LiteralArb |= (uint)green << 8;
} }
} }
hTreeGroup.UsePackedTable = hTreeGroup.IsTrivialCode && maxBits < HuffmanUtils.HuffmanPackedBits;
if (hTreeGroup.UsePackedTable)
{
throw new NotImplementedException("use packed table is not implemented yet");
}
} }
} }
private int ReadHuffmanCode(int alphabetSize, int[] codeLengths, 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++)
{
codeLengths[i] = 0;
}
if (simpleCode) if (simpleCode)
{ {
// (i) Simple Code Length Code. // (i) Simple Code Length Code.
@ -177,7 +235,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
codeLengthCodeLengths[WebPConstants.KCodeLengthCodeOrder[i]] = (int)this.bitReader.ReadBits(3); codeLengthCodeLengths[WebPConstants.KCodeLengthCodeOrder[i]] = (int)this.bitReader.ReadBits(3);
} }
this.ReadHuffmanCodeLengths(table, 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);

Loading…
Cancel
Save