Browse Source

Fix some decoding bugs

pull/1552/head
Brian Popow 7 years ago
parent
commit
d61ce09b02
  1. 10
      src/ImageSharp/Formats/WebP/HuffmanUtils.cs
  2. 2
      src/ImageSharp/Formats/WebP/Vp8LMetadata.cs
  3. 52
      src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs

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

@ -125,18 +125,22 @@ namespace SixLabors.ImageSharp.Formats.WebP
} }
Span<HuffmanCode> tableSpan = table; Span<HuffmanCode> tableSpan = table;
int tablePos = 0;
for (; count[len] > 0; --count[len]) for (; count[len] > 0; --count[len])
{ {
if ((key & mask) != low) if ((key & mask) != low)
{ {
tableSpan = tableSpan.Slice(tableSize); tableSpan = tableSpan.Slice(tableSize);
tablePos += tableSize;
tableBits = NextTableBitSize(count, len, rootBits); tableBits = NextTableBitSize(count, len, rootBits);
tableSize = 1 << tableBits; tableSize = 1 << tableBits;
totalSize += tableSize; totalSize += tableSize;
low = key & mask; low = key & mask;
table[low].BitsUsed = tableBits + rootBits; table[low] = new HuffmanCode
// TODO: fix this {
// table[low].Value = ((table - rootTable) - low); BitsUsed = tableBits + rootBits,
Value = (uint)(tablePos - low)
};
} }
var huffmanCode = new HuffmanCode var huffmanCode = new HuffmanCode

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

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
public int HuffmanXSize { get; set; } public int HuffmanXSize { get; set; }
public int[] HuffmanImage { get; set; } public uint[] HuffmanImage { get; set; }
public int NumHTreeGroups { get; set; } public int NumHTreeGroups { get; set; }

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

@ -108,15 +108,19 @@ namespace SixLabors.ImageSharp.Formats.WebP
private uint[] DecodeImageStream(int xSize, int ySize, bool isLevel0) private uint[] DecodeImageStream(int xSize, int ySize, bool isLevel0)
{ {
this.ReadTransformations(); if (isLevel0)
{
this.ReadTransformations();
}
// Read color cache, if present. // Read color cache, if present.
bool colorCachePresent = this.bitReader.ReadBit(); bool colorCachePresent = this.bitReader.ReadBit();
int colorCacheBits = 0; int colorCacheBits = 0;
int colorCacheSize = 0; int colorCacheSize = 0;
var colorCache = new ColorCache(); ColorCache colorCache = null;
if (colorCachePresent) if (colorCachePresent)
{ {
colorCache = new ColorCache();
colorCacheBits = (int)this.bitReader.ReadBits(4); colorCacheBits = (int)this.bitReader.ReadBits(4);
colorCacheSize = 1 << colorCacheBits; colorCacheSize = 1 << colorCacheBits;
if (!(colorCacheBits >= 1 && colorCacheBits <= WebPConstants.MaxColorCacheBits)) if (!(colorCacheBits >= 1 && colorCacheBits <= WebPConstants.MaxColorCacheBits))
@ -184,7 +188,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
} }
else else
{ {
this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Green]); code = (int)this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Green]);
} }
if (this.bitReader.IsEndOfStream()) if (this.bitReader.IsEndOfStream())
@ -301,22 +305,35 @@ namespace SixLabors.ImageSharp.Formats.WebP
private Vp8LMetadata ReadHuffmanCodes(int xSize, int ySize, int colorCacheBits, bool allowRecursion) private Vp8LMetadata ReadHuffmanCodes(int xSize, int ySize, int colorCacheBits, bool allowRecursion)
{ {
var metadata = new Vp8LMetadata();
int maxAlphabetSize = 0; int maxAlphabetSize = 0;
int numHTreeGroups = 1; int numHTreeGroups = 1;
int numHTreeGroupsMax = 1; int numHTreeGroupsMax = 1;
// If the next bit is zero, there is only one meta Huffman code used everywhere in the image. No more data is stored. // If the next bit is zero, there is only one meta Huffman code used everywhere in the image. No more data is stored.
// If this bit is one, the image uses multiple meta Huffman codes. These meta Huffman codes are stored as an entropy image. // If this bit is one, the image uses multiple meta Huffman codes. These meta Huffman codes are stored as an entropy image.
bool isEntropyImage = this.bitReader.ReadBit(); if (allowRecursion && this.bitReader.ReadBit())
if (allowRecursion && isEntropyImage)
{ {
// Use meta Huffman codes. // Use meta Huffman codes.
uint huffmanPrecision = this.bitReader.ReadBits(3) + 2; uint huffmanPrecision = this.bitReader.ReadBits(3) + 2;
int huffmanXSize = this.SubSampleSize(xSize, (int)huffmanPrecision); int huffmanXSize = this.SubSampleSize(xSize, (int)huffmanPrecision);
int huffmanYSize = this.SubSampleSize(ySize, (int)huffmanPrecision); int huffmanYSize = this.SubSampleSize(ySize, (int)huffmanPrecision);
int huffmanPixs = huffmanXSize * huffmanYSize; int huffmanPixs = huffmanXSize * huffmanYSize;
// TODO: decode entropy image uint[] huffmanImage = this.DecodeImageStream(huffmanXSize, huffmanYSize, false);
return new Vp8LMetadata(); metadata.HuffmanSubSampleBits = (int)huffmanPrecision;
for (int i = 0; i < huffmanPixs; ++i)
{
// The huffman data is stored in red and green bytes.
uint group = (huffmanImage[i] >> 8) & 0xffff;
huffmanImage[i] = group;
if (group >= numHTreeGroupsMax)
{
numHTreeGroupsMax = (int)group + 1;
}
}
numHTreeGroups = numHTreeGroupsMax;
metadata.HuffmanImage = huffmanImage;
} }
// Find maximum alphabet size for the hTree group. // Find maximum alphabet size for the hTree group.
@ -409,13 +426,9 @@ namespace SixLabors.ImageSharp.Formats.WebP
} }
} }
var metadata = new Vp8LMetadata() metadata.NumHTreeGroups = numHTreeGroups;
{ metadata.HTreeGroups = hTreeGroups;
// TODO: initialize huffman_image_ metadata.HuffmanTables = huffmanTables;
NumHTreeGroups = numHTreeGroups,
HTreeGroups = hTreeGroups,
HuffmanTables = huffmanTables,
};
return metadata; return metadata;
} }
@ -476,7 +489,6 @@ namespace SixLabors.ImageSharp.Formats.WebP
private void ReadHuffmanCodeLengths(HuffmanCode[] table, int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths) private void ReadHuffmanCodeLengths(HuffmanCode[] table, int[] codeLengthCodeLengths, int numSymbols, int[] codeLengths)
{ {
Span<HuffmanCode> tableSpan = table.AsSpan();
int maxSymbol; int maxSymbol;
int symbol = 0; int symbol = 0;
int prevCodeLen = WebPConstants.DefaultCodeLength; int prevCodeLen = WebPConstants.DefaultCodeLength;
@ -498,7 +510,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
while (symbol < numSymbols) while (symbol < numSymbols)
{ {
if (maxSymbol-- == 0) if (maxSymbol-- is 0)
{ {
break; break;
} }
@ -732,9 +744,9 @@ namespace SixLabors.ImageSharp.Formats.WebP
return hCode.BitsUsed; return hCode.BitsUsed;
} }
private int GetMetaIndex(int[] image, int xSize, int bits, int x, int y) private uint GetMetaIndex(uint[] image, int xSize, int bits, int x, int y)
{ {
if (bits == 0) if (bits is 0)
{ {
return 0; return 0;
} }
@ -744,8 +756,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
private HTreeGroup[] GetHTreeGroupForPos(Vp8LMetadata metadata, int x, int y) private HTreeGroup[] GetHTreeGroupForPos(Vp8LMetadata metadata, int x, int y)
{ {
int metaIndex = this.GetMetaIndex(metadata.HuffmanImage, metadata.HuffmanXSize, metadata.HuffmanSubSampleBits, x, y); uint metaIndex = this.GetMetaIndex(metadata.HuffmanImage, metadata.HuffmanXSize, metadata.HuffmanSubSampleBits, x, y);
return metadata.HTreeGroups.AsSpan(metaIndex).ToArray(); return metadata.HTreeGroups.AsSpan((int)metaIndex).ToArray();
} }
} }
} }

Loading…
Cancel
Save