diff --git a/src/ImageSharp/Formats/WebP/Lossless/BackwardReferenceEncoder.cs b/src/ImageSharp/Formats/WebP/Lossless/BackwardReferenceEncoder.cs
index 942579487a..8af42a8b49 100644
--- a/src/ImageSharp/Formats/WebP/Lossless/BackwardReferenceEncoder.cs
+++ b/src/ImageSharp/Formats/WebP/Lossless/BackwardReferenceEncoder.cs
@@ -25,11 +25,6 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
private const int WindowOffsetsSizeMax = 32;
- ///
- /// Minimum block size for backward references.
- ///
- private const int MinBlockSize = 256;
-
///
/// The number of bits for the window size.
///
@@ -135,7 +130,6 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
uint bestBgra;
int minPos = (basePosition > windowSize) ? basePosition - windowSize : 0;
int lengthMax = (maxLen < 256) ? maxLen : 256;
- uint maxBasePosition;
pos = (int)chain[basePosition];
int currLength;
@@ -193,7 +187,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
// We have the best match but in case the two intervals continue matching
// to the left, we have the best matches for the left-extended pixels.
- maxBasePosition = (uint)basePosition;
+ var maxBasePosition = (uint)basePosition;
while (true)
{
p.OffsetLength[basePosition] = (bestDistance << MaxLengthBits) | (uint)bestLength;
@@ -432,15 +426,15 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
private static void BackwardReferencesTraceBackwards(int xSize, int ySize, Span bgra, int cacheBits, Vp8LHashChain hashChain, Vp8LBackwardRefs refsSrc, Vp8LBackwardRefs refsDst)
{
int distArraySize = xSize * ySize;
- var distArray = new short[distArraySize];
+ var distArray = new ushort[distArraySize];
BackwardReferencesHashChainDistanceOnly(xSize, ySize, bgra, cacheBits, hashChain, refsSrc, distArray);
int chosenPathSize = TraceBackwards(distArray, distArraySize);
- Span chosenPath = distArray.AsSpan(distArraySize - chosenPathSize);
+ Span chosenPath = distArray.AsSpan(distArraySize - chosenPathSize);
BackwardReferencesHashChainFollowChosenPath(bgra, cacheBits, chosenPath, chosenPathSize, hashChain, refsDst);
}
- private static void BackwardReferencesHashChainDistanceOnly(int xSize, int ySize, Span bgra, int cacheBits, Vp8LHashChain hashChain, Vp8LBackwardRefs refs, short[] distArray)
+ private static void BackwardReferencesHashChainDistanceOnly(int xSize, int ySize, Span bgra, int cacheBits, Vp8LHashChain hashChain, Vp8LBackwardRefs refs, ushort[] distArray)
{
int pixCount = xSize * ySize;
bool useColorCache = cacheBits > 0;
@@ -502,17 +496,15 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
if (i + len - 1 > reach)
{
- int offsetJ = 0;
int lenJ = 0;
int j;
for (j = i; j <= reach; ++j)
{
- offset = hashChain.FindOffset(j + 1);
- len = hashChain.FindLength(j + 1);
+ int offsetJ = hashChain.FindOffset(j + 1);
+ lenJ = hashChain.FindLength(j + 1);
if (offsetJ != offset)
{
- offset = hashChain.FindOffset(j);
- len = hashChain.FindLength(j);
+ lenJ = hashChain.FindLength(j);
break;
}
}
@@ -533,14 +525,14 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
}
}
- private static int TraceBackwards(short[] distArray, int distArraySize)
+ private static int TraceBackwards(ushort[] distArray, int distArraySize)
{
int chosenPathSize = 0;
int pathPos = distArraySize;
int curPos = distArraySize - 1;
while (curPos >= 0)
{
- short cur = distArray[curPos];
+ ushort cur = distArray[curPos];
pathPos--;
chosenPathSize++;
distArray[pathPos] = cur;
@@ -550,7 +542,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
return chosenPathSize;
}
- private static void BackwardReferencesHashChainFollowChosenPath(Span bgra, int cacheBits, Span chosenPath, int chosenPathSize, Vp8LHashChain hashChain, Vp8LBackwardRefs backwardRefs)
+ private static void BackwardReferencesHashChainFollowChosenPath(Span bgra, int cacheBits, Span chosenPath, int chosenPathSize, Vp8LHashChain hashChain, Vp8LBackwardRefs backwardRefs)
{
bool useColorCache = cacheBits > 0;
var colorCache = new ColorCache();
@@ -606,7 +598,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
}
}
- private static void AddSingleLiteralWithCostModel(Span bgra, ColorCache colorCache, CostModel costModel, int idx, bool useColorCache, float prevCost, float[] cost, short[] distArray)
+ private static void AddSingleLiteralWithCostModel(Span bgra, ColorCache colorCache, CostModel costModel, int idx, bool useColorCache, float prevCost, float[] cost, ushort[] distArray)
{
double costVal = prevCost;
uint color = bgra[idx];
@@ -965,7 +957,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
if (ix >= 0)
{
// Color cache contains bgraLiteral
- v = PixOrCopy.CreateCacheIdx(ix);
+ PixOrCopy.CreateCacheIdx(ix);
}
else
{
@@ -983,8 +975,6 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
}
}
}
-
- // TODO: VP8LColorCacheClear(colorCache)?
}
private static void BackwardReferences2DLocality(int xSize, Vp8LBackwardRefs refs)
diff --git a/src/ImageSharp/Formats/WebP/Lossless/CostManager.cs b/src/ImageSharp/Formats/WebP/Lossless/CostManager.cs
index d912e2e28e..bba82d10e7 100644
--- a/src/ImageSharp/Formats/WebP/Lossless/CostManager.cs
+++ b/src/ImageSharp/Formats/WebP/Lossless/CostManager.cs
@@ -14,11 +14,10 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
{
private CostInterval head;
- public CostManager(short[] distArray, int pixCount, CostModel costModel)
+ public CostManager(ushort[] distArray, int pixCount, CostModel costModel)
{
int costCacheSize = (pixCount > BackwardReferenceEncoder.MaxLength) ? BackwardReferenceEncoder.MaxLength : pixCount;
- this.Intervals = new List();
this.CacheIntervals = new List();
this.CostCache = new List();
this.Costs = new float[pixCount];
@@ -85,9 +84,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
public float[] Costs { get; }
- public short[] DistArray { get; }
-
- public List Intervals { get; }
+ public ushort[] DistArray { get; }
public List CacheIntervals { get; }
@@ -99,7 +96,6 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
public void UpdateCostAtIndex(int i, bool doCleanIntervals)
{
CostInterval current = this.head;
- using List.Enumerator intervalEnumerator = this.Intervals.GetEnumerator();
while (current != null && current.Start <= i)
{
CostInterval next = current.Next;
@@ -142,7 +138,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
if (this.Costs[j] > costTmp)
{
this.Costs[j] = costTmp;
- this.DistArray[j] = (short)(k + 1);
+ this.DistArray[j] = (ushort)(k + 1);
}
}
@@ -150,14 +146,13 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
}
CostInterval interval = this.head;
- for (int i = 0; i < this.CacheIntervalsSize && this.CacheIntervals[i].Start < len; i++)
+ for (int i = 0; i < this.CacheIntervalsSize && this.CacheIntervals[i].Start < len; ++i)
{
// Define the intersection of the ith interval with the new one.
int start = position + this.CacheIntervals[i].Start;
int end = position + (this.CacheIntervals[i].End > len ? len : this.CacheIntervals[i].End);
float cost = (float)(distanceCost + this.CacheIntervals[i].Cost);
- var idx = i;
CostInterval intervalNext;
for (; interval != null && interval.Start < end; interval = intervalNext)
{
@@ -203,7 +198,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
// We have to split the old interval as it fully contains the new one.
int endOriginal = interval.End;
interval.End = start;
- this.InsertInterval(interval, interval.Cost, idx, end, endOriginal);
+ this.InsertInterval(interval, interval.Cost, interval.Index, end, endOriginal);
break;
}
else
@@ -317,7 +312,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
if (this.Costs[i] > cost)
{
this.Costs[i] = cost;
- this.DistArray[i] = (short)(k + 1);
+ this.DistArray[i] = (ushort)(k + 1);
}
}
}
diff --git a/src/ImageSharp/Formats/WebP/Lossless/HistogramBinInfo.cs b/src/ImageSharp/Formats/WebP/Lossless/HistogramBinInfo.cs
index b75df6505a..e045579597 100644
--- a/src/ImageSharp/Formats/WebP/Lossless/HistogramBinInfo.cs
+++ b/src/ImageSharp/Formats/WebP/Lossless/HistogramBinInfo.cs
@@ -13,6 +13,6 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
///
/// Number of combine failures per binId.
///
- public short NumCombineFailures;
+ public ushort NumCombineFailures;
}
}
diff --git a/src/ImageSharp/Formats/WebP/Lossless/HistogramEncoder.cs b/src/ImageSharp/Formats/WebP/Lossless/HistogramEncoder.cs
index a1ca4108ab..1497ca2447 100644
--- a/src/ImageSharp/Formats/WebP/Lossless/HistogramEncoder.cs
+++ b/src/ImageSharp/Formats/WebP/Lossless/HistogramEncoder.cs
@@ -26,17 +26,16 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
private const uint NonTrivialSym = 0xffffffff;
- private const short InvalidHistogramSymbol = short.MaxValue;
+ private const ushort InvalidHistogramSymbol = ushort.MaxValue;
- public static void GetHistoImageSymbols(int xSize, int ySize, Vp8LBackwardRefs refs, int quality, int histoBits, int cacheBits, List imageHisto, Vp8LHistogram tmpHisto, short[] histogramSymbols)
+ public static void GetHistoImageSymbols(int xSize, int ySize, Vp8LBackwardRefs refs, int quality, int histoBits, int cacheBits, List imageHisto, Vp8LHistogram tmpHisto, ushort[] histogramSymbols)
{
int histoXSize = histoBits > 0 ? LosslessUtils.SubSampleSize(xSize, histoBits) : 1;
int histoYSize = histoBits > 0 ? LosslessUtils.SubSampleSize(ySize, histoBits) : 1;
int imageHistoRawSize = histoXSize * histoYSize;
int entropyCombineNumBins = BinSize;
- var mapTmp = new short[imageHistoRawSize];
- var clusterMappings = new short[imageHistoRawSize];
- int numUsed = imageHistoRawSize;
+ var mapTmp = new ushort[imageHistoRawSize];
+ var clusterMappings = new ushort[imageHistoRawSize];
var origHisto = new List(imageHistoRawSize);
for (int i = 0; i < imageHistoRawSize; i++)
{
@@ -47,13 +46,12 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
HistogramBuild(xSize, histoBits, refs, origHisto);
// Copies the histograms and computes its bitCost. histogramSymbols is optimized.
- HistogramCopyAndAnalyze(origHisto, imageHisto, histogramSymbols);
- numUsed = imageHisto.Count(h => h != null);
+ int numUsed = HistogramCopyAndAnalyze(origHisto, imageHisto, histogramSymbols);
var entropyCombine = (numUsed > entropyCombineNumBins * 2) && (quality < 100);
if (entropyCombine)
{
- short[] binMap = mapTmp;
+ ushort[] binMap = mapTmp;
var numClusters = numUsed;
double combineCostFactor = GetCombineCostFactor(imageHistoRawSize, quality);
HistogramAnalyzeEntropyBin(imageHisto, binMap);
@@ -128,7 +126,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
/// Partition histograms to different entropy bins for three dominant (literal,
/// red and blue) symbol costs and compute the histogram aggregate bitCost.
///
- private static void HistogramAnalyzeEntropyBin(List histograms, short[] binMap)
+ private static void HistogramAnalyzeEntropyBin(List histograms, ushort[] binMap)
{
int histoSize = histograms.Count;
var costRange = new DominantCostRange();
@@ -153,13 +151,13 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
continue;
}
- binMap[i] = (short)costRange.GetHistoBinIndex(histograms[i], NumPartitions);
+ binMap[i] = (ushort)costRange.GetHistoBinIndex(histograms[i], NumPartitions);
}
}
- private static void HistogramCopyAndAnalyze(List origHistograms, List histograms, short[] histogramSymbols)
+ private static int HistogramCopyAndAnalyze(List origHistograms, List histograms, ushort[] histogramSymbols)
{
- for (int clusterId = 0, i = 0; i < origHistograms.Count; i++)
+ for (int clusterId = 0, i = 0; i < origHistograms.Count; ++i)
{
Vp8LHistogram origHistogram = origHistograms[i];
origHistogram.UpdateHistogramCost();
@@ -174,12 +172,15 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
else
{
histograms[i] = (Vp8LHistogram)origHistogram.DeepClone();
- histogramSymbols[i] = (short)clusterId++;
+ histogramSymbols[i] = (ushort)clusterId++;
}
}
+
+ int numUsed = histogramSymbols.Count(h => h != InvalidHistogramSymbol);
+ return numUsed;
}
- private static void HistogramCombineEntropyBin(List histograms, short[] clusters, short[] clusterMappings, Vp8LHistogram curCombo, short[] binMap, int numBins, double combineCostFactor)
+ private static void HistogramCombineEntropyBin(List histograms, ushort[] clusters, ushort[] clusterMappings, Vp8LHistogram curCombo, ushort[] binMap, int numBins, double combineCostFactor)
{
var binInfo = new HistogramBinInfo[BinSize];
for (int idx = 0; idx < numBins; idx++)
@@ -191,7 +192,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
// By default, a cluster matches itself.
for (int idx = 0; idx < histograms.Count; idx++)
{
- clusterMappings[idx] = (short)idx;
+ clusterMappings[idx] = (ushort)idx;
}
var indicesToRemove = new List();
@@ -253,7 +254,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
/// Given a Histogram set, the mapping of clusters 'clusterMapping' and the
/// current assignment of the cells in 'symbols', merge the clusters and assign the smallest possible clusters values.
///
- private static void OptimizeHistogramSymbols(short[] clusterMappings, int numClusters, short[] clusterMappingsTmp, short[] symbols)
+ private static void OptimizeHistogramSymbols(ushort[] clusterMappings, int numClusters, ushort[] clusterMappingsTmp, ushort[] symbols)
{
bool doContinue = true;
@@ -274,7 +275,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
if (k != clusterMappings[i])
{
doContinue = true;
- clusterMappings[i] = (short)k;
+ clusterMappings[i] = (ushort)k;
}
}
}
@@ -295,7 +296,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
if (cluster > 0 && clusterMappingsTmp[cluster] == 0)
{
clusterMax++;
- clusterMappingsTmp[cluster] = (short)clusterMax;
+ clusterMappingsTmp[cluster] = (ushort)clusterMax;
}
symbols[i] = clusterMappingsTmp[cluster];
@@ -522,7 +523,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
}
}
- private static void HistogramRemap(List input, List output, short[] symbols)
+ private static void HistogramRemap(List input, List output, ushort[] symbols)
{
int inSize = input.Count;
int outSize = output.Count;
@@ -549,7 +550,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
}
}
- symbols[i] = (short)bestOut;
+ symbols[i] = (ushort)bestOut;
}
}
else
diff --git a/src/ImageSharp/Formats/WebP/Lossless/HuffmanUtils.cs b/src/ImageSharp/Formats/WebP/Lossless/HuffmanUtils.cs
index 414c607ad1..2e0805c28e 100644
--- a/src/ImageSharp/Formats/WebP/Lossless/HuffmanUtils.cs
+++ b/src/ImageSharp/Formats/WebP/Lossless/HuffmanUtils.cs
@@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
public static void OptimizeHuffmanForRle(int length, bool[] goodForRle, uint[] counts)
{
// 1) Let's make the Huffman code more compatible with rle encoding.
- for (; length >= 0; length--)
+ for (; length >= 0; --length)
{
if (length == 0)
{
@@ -63,13 +63,13 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
// Mark any seq of non-0's that is longer as 7 as a goodForRle.
uint symbol = counts[0];
int stride = 0;
- for (int i = 0; i < length + 1; i++)
+ for (int i = 0; i < length + 1; ++i)
{
if (i == length || counts[i] != symbol)
{
if ((symbol == 0 && stride >= 5) || (symbol != 0 && stride >= 7))
{
- for (int k = 0; k < stride; k++)
+ for (int k = 0; k < stride; ++k)
{
goodForRle[i - k - 1] = true;
}
@@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
}
else
{
- stride++;
+ ++stride;
}
}
@@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
stride = 0;
uint limit = counts[0];
uint sum = 0;
- for (int i = 0; i < length; i++)
+ for (int i = 0; i < length + 1; ++i)
{
var valuesShouldBeCollapsedToStrideAverage = ValuesShouldBeCollapsedToStrideAverage((int)counts[i], (int)limit);
if (i == length || goodForRle[i] || (i != 0 && goodForRle[i - 1]) || !valuesShouldBeCollapsedToStrideAverage)
@@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
count = 0;
}
- for (k = 0; k < stride; k++)
+ for (k = 0; k < stride; ++k)
{
// We don't want to change value at counts[i],
// that is already belonging to the next stride. Thus - 1.
@@ -139,7 +139,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
}
}
- stride++;
+ ++stride;
if (i != length)
{
sum += counts[i];
@@ -165,11 +165,11 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
uint countMin;
int treeSizeOrig = 0;
- for (int i = 0; i < histogramSize; i++)
+ for (int i = 0; i < histogramSize; ++i)
{
if (histogram[i] != 0)
{
- treeSizeOrig++;
+ ++treeSizeOrig;
}
}
diff --git a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
index 8b1a44fe57..e5b53c6f85 100644
--- a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
+++ b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
@@ -401,7 +401,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
private void EncodeImage(Span bgra, Vp8LHashChain hashChain, Vp8LBackwardRefs[] refsArray, int width, int height, int quality, bool useCache, CrunchConfig config, int cacheBits, int histogramBits, int initBytePosition)
{
int histogramImageXySize = LosslessUtils.SubSampleSize(width, histogramBits) * LosslessUtils.SubSampleSize(height, histogramBits);
- var histogramSymbols = new short[histogramImageXySize];
+ var histogramSymbols = new ushort[histogramImageXySize];
var huffTree = new HuffmanTree[3 * WebPConstants.CodeLengthCodes];
for (int i = 0; i < huffTree.Length; i++)
{
@@ -412,6 +412,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
{
if (cacheBits == 0)
{
+ // TODO: not sure if this should be 10 or 11. Original code comment says "The maximum allowed limit is 11.", but the value itself is 10.
cacheBits = WebPConstants.MaxColorCacheBits;
}
}
@@ -485,7 +486,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
using IMemoryOwner histogramBgraBuffer = this.memoryAllocator.Allocate(histogramImageXySize);
Span histogramBgra = histogramBgraBuffer.GetSpan();
int maxIndex = 0;
- for (int i = 0; i < histogramImageXySize; i++)
+ for (int i = 0; i < histogramImageXySize; ++i)
{
int symbolIndex = histogramSymbols[i] & 0xffff;
histogramBgra[i] = (uint)(symbolIndex << 8);
@@ -502,7 +503,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
// Store Huffman codes.
// Find maximum number of symbols for the huffman tree-set.
int maxTokens = 0;
- for (int i = 0; i < 5 * histogramImage.Count; i++)
+ for (int i = 0; i < 5 * histogramImage.Count; ++i)
{
HuffmanTreeCode codes = huffmanCodes[i];
if (maxTokens < codes.NumSymbols)
@@ -517,7 +518,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
tokens[i] = new HuffmanTreeToken();
}
- for (int i = 0; i < 5 * histogramImage.Count; i++)
+ for (int i = 0; i < 5 * histogramImage.Count; ++i)
{
HuffmanTreeCode codes = huffmanCodes[i];
this.StoreHuffmanCode(huffTree, tokens, codes);
@@ -531,7 +532,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
// TODO: Keep track of the smallest image so far.
if (bitWriterBest != null && this.bitWriter.NumBytes() < bitWriterBest.NumBytes())
{
- // TODO : This was done in the reference by swapping references, this will be slower
+ // TODO: This was done in the reference by swapping references, this will be slower
bitWriterBest = this.bitWriter.Clone();
}
}
@@ -606,7 +607,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
private void EncodeImageNoHuffman(Span bgra, Vp8LHashChain hashChain, Vp8LBackwardRefs refsTmp1, Vp8LBackwardRefs refsTmp2, int width, int height, int quality)
{
int cacheBits = 0;
- var histogramSymbols = new short[1]; // Only one tree, one symbol.
+ var histogramSymbols = new ushort[1]; // Only one tree, one symbol.
// TODO: Can HuffmanTreeCode be struct
var huffmanCodes = new HuffmanTreeCode[5];
@@ -652,7 +653,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
// Find maximum number of symbols for the huffman tree-set.
int maxTokens = 0;
- for (int i = 0; i < 5; i++)
+ for (int i = 0; i < 5; ++i)
{
HuffmanTreeCode codes = huffmanCodes[i];
if (maxTokens < codes.NumSymbols)
@@ -662,13 +663,13 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
}
var tokens = new HuffmanTreeToken[maxTokens];
- for (int i = 0; i < tokens.Length; i++)
+ for (int i = 0; i < tokens.Length; ++i)
{
tokens[i] = new HuffmanTreeToken();
}
// Store Huffman codes.
- for (int i = 0; i < 5; i++)
+ for (int i = 0; i < 5; ++i)
{
HuffmanTreeCode codes = huffmanCodes[i];
this.StoreHuffmanCode(huffTree, tokens, codes);
@@ -849,7 +850,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
}
}
- private void StoreImageToBitMask(int width, int histoBits, Vp8LBackwardRefs backwardRefs, short[] histogramSymbols, HuffmanTreeCode[] huffmanCodes)
+ private void StoreImageToBitMask(int width, int histoBits, Vp8LBackwardRefs backwardRefs, ushort[] histogramSymbols, HuffmanTreeCode[] huffmanCodes)
{
int histoXSize = histoBits > 0 ? LosslessUtils.SubSampleSize(width, histoBits) : 1;
int tileMask = (histoBits == 0) ? 0 : -(1 << histoBits);
diff --git a/src/ImageSharp/Formats/WebP/Lossless/Vp8LHistogram.cs b/src/ImageSharp/Formats/WebP/Lossless/Vp8LHistogram.cs
index 78420185bc..dd5c9ebda5 100644
--- a/src/ImageSharp/Formats/WebP/Lossless/Vp8LHistogram.cs
+++ b/src/ImageSharp/Formats/WebP/Lossless/Vp8LHistogram.cs
@@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
this.Distance = new uint[WebPConstants.NumDistanceCodes];
var literalSize = WebPConstants.NumLiteralCodes + WebPConstants.NumLengthCodes + (1 << WebPConstants.MaxColorCacheBits);
- this.Literal = new uint[literalSize];
+ this.Literal = new uint[literalSize + 1];
// 5 for literal, red, blue, alpha, distance.
this.IsUsed = new bool[5];
diff --git a/src/ImageSharp/Formats/WebP/Lossless/WebPLosslessDecoder.cs b/src/ImageSharp/Formats/WebP/Lossless/WebPLosslessDecoder.cs
index bf59394d3c..943d18397e 100644
--- a/src/ImageSharp/Formats/WebP/Lossless/WebPLosslessDecoder.cs
+++ b/src/ImageSharp/Formats/WebP/Lossless/WebPLosslessDecoder.cs
@@ -145,7 +145,10 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
if (isColorCachePresent)
{
colorCacheBits = (int)this.bitReader.ReadValue(4);
- bool colorCacheBitsIsValid = colorCacheBits >= 1 && colorCacheBits <= WebPConstants.MaxColorCacheBits;
+
+ // Note: According to webpinfo color cache bits of 11 are valid, even though 10 is defined in the source code as maximum.
+ // That is why 11 bits is also considered valid here.
+ bool colorCacheBitsIsValid = colorCacheBits >= 1 && colorCacheBits <= (WebPConstants.MaxColorCacheBits + 1);
if (!colorCacheBitsIsValid)
{
WebPThrowHelper.ThrowImageFormatException("Invalid color cache bits found");
@@ -162,11 +165,6 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
decoder.Metadata.ColorCache = new ColorCache();
colorCacheSize = 1 << colorCacheBits;
decoder.Metadata.ColorCacheSize = colorCacheSize;
- if (!(colorCacheBits >= 1 && colorCacheBits <= WebPConstants.MaxColorCacheBits))
- {
- WebPThrowHelper.ThrowImageFormatException("Invalid color cache bits found");
- }
-
decoder.Metadata.ColorCache.Init(colorCacheBits);
}
else
diff --git a/src/ImageSharp/Formats/WebP/WebPConstants.cs b/src/ImageSharp/Formats/WebP/WebPConstants.cs
index edec77ad88..71fab497d9 100644
--- a/src/ImageSharp/Formats/WebP/WebPConstants.cs
+++ b/src/ImageSharp/Formats/WebP/WebPConstants.cs
@@ -114,9 +114,9 @@ namespace SixLabors.ImageSharp.Formats.WebP
public const int MaxPaletteSize = 256;
///
- /// Maximum number of color cache bits is 11.
+ /// Maximum number of color cache bits is 10.
///
- public const int MaxColorCacheBits = 11;
+ public const int MaxColorCacheBits = 10;
///
/// The maximum number of allowed transforms in a VP8L bitstream.