Browse Source

Continue with ReadHuffmanCodes

pull/1552/head
Brian Popow 6 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>
internal class HTreeGroup
{
public HTreeGroup()
{
HTree = new List<HuffmanCode[]>(WebPConstants.HuffmanCodesPerMetaCode);
}
/// <summary>
/// This has a maximum of HuffmanCodesPerMetaCode (5) entrys.
/// </summary>
public List<HuffmanCode> HTree { get; set; }
public List<HuffmanCode[]> HTree { get; private set; }
/// <summary>
/// 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>
/// If is_trivial_literal is true, this is the ARGB value of the pixel, with Green channel being set to zero.
/// </summary>
public int LiteralArb { get; set; }
public uint LiteralArb { get; set; }
/// <summary>
/// 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 HuffmanPackedBits = 6;
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.NotNull(codeLengths, nameof(codeLengths));
@ -38,7 +40,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
return 0;
}
++count[codeLengths[symbol]];
count[codeLengths[symbol]]++;
}
// Generate offsets into sorted symbol table by code length.
@ -102,7 +104,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
BitsUsed = len,
Value = sorted[symbol++]
};
ReplicateValue(table.AsSpan(key), step, tableSize, huffmanCode);
ReplicateValue(table.Slice(key), step, tableSize, huffmanCode);
key = GetNextKey(key, len);
}
}
@ -118,7 +120,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
return 0;
}
Span<HuffmanCode> tableSpan = table.AsSpan();
Span<HuffmanCode> tableSpan = table;
for (; count[len] > 0; --count[len])
{
if ((key & mask) != low)

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

@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SixLabors.ImageSharp.Memory;
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[] kTableSize =
private static readonly int[] kTableSize =
{
FIXED_TABLE_SIZE + 654,
FIXED_TABLE_SIZE + 656,
@ -41,6 +42,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
FIXED_TABLE_SIZE + 2704
};
private static readonly byte[] kLiteralMap =
{
0, 1, 1, 1, 0
};
public WebPLosslessDecoder(Vp8LBitReader bitReader, int imageDataSize)
{
this.bitReader = bitReader;
@ -108,12 +114,16 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
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++)
{
hTreeGroups[i] = new HTreeGroup();
HTreeGroup hTreeGroup = hTreeGroups[i];
int size;
int totalSize = 0;
int isTrivialLiteral = 1;
bool isTrivialLiteral = true;
int maxBits = 0;
var codeLengths = new int[maxAlphabetSize];
for (int j = 0; j < WebPConstants.HuffmanCodesPerMetaCode; j++)
@ -121,24 +131,72 @@ namespace SixLabors.ImageSharp.Formats.WebP
int alphabetSize = WebPConstants.kAlphabetSize[j];
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 (size is 0)
if (j <= (int)HuffIndex.Alpha)
{
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();
for (int i = 0; i < alphabetSize; i++)
{
codeLengths[i] = 0;
}
if (simpleCode)
{
// (i) Simple Code Length Code.
@ -177,7 +235,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
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);

Loading…
Cancel
Save