Browse Source

Fix some issues:

- Fix wrong palette code bits init in CalculateBestCacheSize
- Fix wrong slice start index in PrepareMapToPalette
- PixOrCopy: Change len from short to ushort
pull/1552/head
Brian Popow 6 years ago
parent
commit
8538db75e4
  1. 26
      src/ImageSharp/Formats/WebP/Lossless/BackwardReferenceEncoder.cs
  2. 3
      src/ImageSharp/Formats/WebP/Lossless/HuffmanUtils.cs
  3. 6
      src/ImageSharp/Formats/WebP/Lossless/PixOrCopy.cs
  4. 33
      src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
  5. 2
      src/ImageSharp/Formats/WebP/Lossless/Vp8LHistogram.cs

26
src/ImageSharp/Formats/WebP/Lossless/BackwardReferenceEncoder.cs

@ -230,12 +230,10 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
} }
/// <summary> /// <summary>
/// Evaluates best possible backward references for specified quality. /// Evaluates best possible backward references for specified quality. The input cacheBits to 'GetBackwardReferences'
/// The input cacheBits to 'GetBackwardReferences' sets the maximum cache /// sets the maximum cache bits to use (passing 0 implies disabling the local color cache).
/// bits to use (passing 0 implies disabling the local color cache).
/// The optimal cache bits is evaluated and set for the cacheBits parameter. /// The optimal cache bits is evaluated and set for the cacheBits parameter.
/// The return value is the pointer to the best of the two backward refs viz, /// The return value is the pointer to the best of the two backward refs viz, refs[0] or refs[1].
/// refs[0] or refs[1].
/// </summary> /// </summary>
public static Vp8LBackwardRefs GetBackwardReferences( public static Vp8LBackwardRefs GetBackwardReferences(
int width, int width,
@ -335,9 +333,9 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
int pos = 0; int pos = 0;
var colorCache = new ColorCache[WebPConstants.MaxColorCacheBits + 1]; var colorCache = new ColorCache[WebPConstants.MaxColorCacheBits + 1];
var histos = new Vp8LHistogram[WebPConstants.MaxColorCacheBits + 1]; var histos = new Vp8LHistogram[WebPConstants.MaxColorCacheBits + 1];
for (int i = 0; i < WebPConstants.MaxColorCacheBits + 1; i++) for (int i = 0; i <= WebPConstants.MaxColorCacheBits; i++)
{ {
histos[i] = new Vp8LHistogram(bestCacheBits); histos[i] = new Vp8LHistogram(paletteCodeBits: i);
colorCache[i] = new ColorCache(); colorCache[i] = new ColorCache();
colorCache[i].Init(i); colorCache[i].Init(i);
} }
@ -369,7 +367,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
{ {
if (colorCache[i].Lookup(key) == pix) if (colorCache[i].Lookup(key) == pix)
{ {
++histos[i].Literal[WebPConstants.NumLiteralCodes + WebPConstants.CodeLengthCodes + key]; ++histos[i].Literal[WebPConstants.NumLiteralCodes + WebPConstants.NumLengthCodes + key];
} }
else else
{ {
@ -563,7 +561,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
if (len != 1) if (len != 1)
{ {
int offset = hashChain.FindOffset(i); int offset = hashChain.FindOffset(i);
backwardRefs.Add(PixOrCopy.CreateCopy((uint)offset, (short)len)); backwardRefs.Add(PixOrCopy.CreateCopy((uint)offset, (ushort)len));
if (useColorCache) if (useColorCache)
{ {
@ -689,7 +687,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
} }
else else
{ {
refs.Add(PixOrCopy.CreateCopy((uint)offset, (short)len)); refs.Add(PixOrCopy.CreateCopy((uint)offset, (ushort)len));
if (useColorCache) if (useColorCache)
{ {
for (j = i; j < i + len; ++j) for (j = i; j < i + len; ++j)
@ -908,7 +906,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
int prevRowLen = (i < xSize) ? 0 : FindMatchLength(bgra.Slice(i), bgra.Slice(i - xSize), 0, maxLen); int prevRowLen = (i < xSize) ? 0 : FindMatchLength(bgra.Slice(i), bgra.Slice(i - xSize), 0, maxLen);
if (rleLen >= prevRowLen && rleLen >= MinLength) if (rleLen >= prevRowLen && rleLen >= MinLength)
{ {
refs.Add(PixOrCopy.CreateCopy(1, (short)rleLen)); refs.Add(PixOrCopy.CreateCopy(1, (ushort)rleLen));
// We don't need to update the color cache here since it is always the // We don't need to update the color cache here since it is always the
// same pixel being copied, and that does not change the color cache state. // same pixel being copied, and that does not change the color cache state.
@ -916,7 +914,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
} }
else if (prevRowLen >= MinLength) else if (prevRowLen >= MinLength)
{ {
refs.Add(PixOrCopy.CreateCopy((uint)xSize, (short)prevRowLen)); refs.Add(PixOrCopy.CreateCopy((uint)xSize, (ushort)prevRowLen));
if (useColorCache) if (useColorCache)
{ {
for (int k = 0; k < prevRowLen; k++) for (int k = 0; k < prevRowLen; k++)
@ -936,7 +934,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
if (useColorCache) if (useColorCache)
{ {
// TODO: VP8LColorCacheClear(); // TODO: VP8LColorCacheClear()?
} }
} }
@ -978,7 +976,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
} }
} }
// TODO: VP8LColorCacheClear(colorCache); // TODO: VP8LColorCacheClear(colorCache)?
} }
private static void BackwardReferences2DLocality(int xSize, Vp8LBackwardRefs refs) private static void BackwardReferences2DLocality(int xSize, Vp8LBackwardRefs refs)

3
src/ImageSharp/Formats/WebP/Lossless/HuffmanUtils.cs

@ -279,13 +279,12 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
{ {
int value = tree.CodeLengths[i]; int value = tree.CodeLengths[i];
int k = i + 1; int k = i + 1;
int runs;
while (k < depthSize && tree.CodeLengths[k] == value) while (k < depthSize && tree.CodeLengths[k] == value)
{ {
k++; k++;
} }
runs = k - i; var runs = k - i;
if (value == 0) if (value == 0)
{ {
tokenPos += CodeRepeatedZeros(runs, tokensArray.AsSpan(tokenPos)); tokenPos += CodeRepeatedZeros(runs, tokensArray.AsSpan(tokenPos));

6
src/ImageSharp/Formats/WebP/Lossless/PixOrCopy.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
{ {
public PixOrCopyMode Mode { get; set; } public PixOrCopyMode Mode { get; set; }
public short Len { get; set; } public ushort Len { get; set; }
public uint BgraOrDistance { get; set; } public uint BgraOrDistance { get; set; }
@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
return retval; return retval;
} }
public static PixOrCopy CreateCopy(uint distance, short len) public static PixOrCopy CreateCopy(uint distance, ushort len)
{ {
var retval = new PixOrCopy() var retval = new PixOrCopy()
{ {
@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
return this.BgraOrDistance; return this.BgraOrDistance;
} }
public short Length() public ushort Length()
{ {
return this.Len; return this.Len;
} }

33
src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs

@ -427,7 +427,16 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
foreach (CrunchSubConfig subConfig in config.SubConfigs) foreach (CrunchSubConfig subConfig in config.SubConfigs)
{ {
Vp8LBackwardRefs refsBest = BackwardReferenceEncoder.GetBackwardReferences(width, height, bgra, quality, subConfig.Lz77, ref cacheBits, hashChain, refsArray[0], refsArray[1]); // TODO : Pass do not cache Vp8LBackwardRefs refsBest = BackwardReferenceEncoder.GetBackwardReferences(
width,
height,
bgra,
quality,
subConfig.Lz77,
ref cacheBits,
hashChain,
refsArray[0],
refsArray[1]); // TODO : Pass do not cache
// Keep the best references aside and use the other element from the first // Keep the best references aside and use the other element from the first
// two as a temporary for later usage. // two as a temporary for later usage.
@ -473,13 +482,13 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
this.bitWriter.PutBits((uint)(writeHistogramImage ? 1 : 0), 1); this.bitWriter.PutBits((uint)(writeHistogramImage ? 1 : 0), 1);
if (writeHistogramImage) if (writeHistogramImage)
{ {
using IMemoryOwner<uint> histogramArgbBuffer = this.memoryAllocator.Allocate<uint>(histogramImageXySize); using IMemoryOwner<uint> histogramBgraBuffer = this.memoryAllocator.Allocate<uint>(histogramImageXySize);
Span<uint> histogramArgb = histogramArgbBuffer.GetSpan(); Span<uint> histogramBgra = histogramBgraBuffer.GetSpan();
int maxIndex = 0; int maxIndex = 0;
for (int i = 0; i < histogramImageXySize; i++) for (int i = 0; i < histogramImageXySize; i++)
{ {
int symbolIndex = histogramSymbols[i] & 0xffff; int symbolIndex = histogramSymbols[i] & 0xffff;
histogramArgb[i] = (uint)(symbolIndex << 8); histogramBgra[i] = (uint)(symbolIndex << 8);
if (symbolIndex >= maxIndex) if (symbolIndex >= maxIndex)
{ {
maxIndex = symbolIndex + 1; maxIndex = symbolIndex + 1;
@ -487,7 +496,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
} }
this.bitWriter.PutBits((uint)(histogramBits - 2), 3); this.bitWriter.PutBits((uint)(histogramBits - 2), 3);
this.EncodeImageNoHuffman(histogramArgb, hashChain, refsTmp, refsArray[2], LosslessUtils.SubSampleSize(width, histogramBits), LosslessUtils.SubSampleSize(height, histogramBits), quality); this.EncodeImageNoHuffman(histogramBgra, hashChain, refsTmp, refsArray[2], LosslessUtils.SubSampleSize(width, histogramBits), LosslessUtils.SubSampleSize(height, histogramBits), quality);
} }
// Store Huffman codes. // Store Huffman codes.
@ -690,7 +699,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
if (count == 0) if (count == 0)
{ {
// emit minimal tree for empty cases // Emit minimal tree for empty cases.
// bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0 // bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0
this.bitWriter.PutBits(0x01, 4); this.bitWriter.PutBits(0x01, 4);
} }
@ -725,10 +734,12 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
int i; int i;
var codeLengthBitDepth = new byte[WebPConstants.CodeLengthCodes]; var codeLengthBitDepth = new byte[WebPConstants.CodeLengthCodes];
var codeLengthBitDepthSymbols = new short[WebPConstants.CodeLengthCodes]; var codeLengthBitDepthSymbols = new short[WebPConstants.CodeLengthCodes];
var huffmanCode = new HuffmanTreeCode(); var huffmanCode = new HuffmanTreeCode
huffmanCode.NumSymbols = WebPConstants.CodeLengthCodes; {
huffmanCode.CodeLengths = codeLengthBitDepth; NumSymbols = WebPConstants.CodeLengthCodes,
huffmanCode.Codes = codeLengthBitDepthSymbols; CodeLengths = codeLengthBitDepth,
Codes = codeLengthBitDepthSymbols
};
this.bitWriter.PutBits(0, 1); this.bitWriter.PutBits(0, 1);
var numTokens = HuffmanUtils.CreateCompressedHuffmanTree(tree, tokens); var numTokens = HuffmanUtils.CreateCompressedHuffmanTree(tree, tokens);
@ -1313,7 +1324,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
/// </summary> /// </summary>
private static void PrepareMapToPalette(Span<uint> palette, int numColors, uint[] sorted, uint[] idxMap) private static void PrepareMapToPalette(Span<uint> palette, int numColors, uint[] sorted, uint[] idxMap)
{ {
palette.Slice(numColors).CopyTo(sorted); palette.Slice(0, numColors).CopyTo(sorted);
Array.Sort(sorted, PaletteCompareColorsForSort); Array.Sort(sorted, PaletteCompareColorsForSort);
for (int i = 0; i < numColors; i++) for (int i = 0; i < numColors; i++)
{ {

2
src/ImageSharp/Formats/WebP/Lossless/Vp8LHistogram.cs

@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
this.Alpha = new uint[WebPConstants.NumLiteralCodes + 1]; this.Alpha = new uint[WebPConstants.NumLiteralCodes + 1];
this.Distance = new uint[WebPConstants.NumDistanceCodes]; this.Distance = new uint[WebPConstants.NumDistanceCodes];
var literalSize = WebPConstants.NumLiteralCodes + WebPConstants.NumLengthCodes + ((this.PaletteCodeBits > 0) ? (1 << this.PaletteCodeBits) : 0); var literalSize = WebPConstants.NumLiteralCodes + WebPConstants.NumLengthCodes + (1 << WebPConstants.MaxColorCacheBits);
this.Literal = new uint[literalSize]; this.Literal = new uint[literalSize];
// 5 for literal, red, blue, alpha, distance. // 5 for literal, red, blue, alpha, distance.

Loading…
Cancel
Save