Browse Source

Cleanup

pull/1552/head
Brian Popow 5 years ago
parent
commit
70b616a566
  1. 13
      src/ImageSharp/Formats/WebP/AlphaDecoder.cs
  2. 2
      src/ImageSharp/Formats/WebP/BitReader/Vp8BitReader.cs
  3. 18
      src/ImageSharp/Formats/WebP/BitWriter/Vp8BitWriter.cs
  4. 2
      src/ImageSharp/Formats/WebP/HistoIx.cs
  5. 21
      src/ImageSharp/Formats/WebP/Lossless/BackwardReferenceEncoder.cs
  6. 20
      src/ImageSharp/Formats/WebP/Lossless/ColorCache.cs
  7. 2
      src/ImageSharp/Formats/WebP/Lossless/CostManager.cs
  8. 5
      src/ImageSharp/Formats/WebP/Lossless/CostModel.cs
  9. 34
      src/ImageSharp/Formats/WebP/Lossless/HistogramEncoder.cs
  10. 2
      src/ImageSharp/Formats/WebP/Lossless/HuffmanTree.cs
  11. 31
      src/ImageSharp/Formats/WebP/Lossless/HuffmanUtils.cs
  12. 38
      src/ImageSharp/Formats/WebP/Lossless/LosslessUtils.cs
  13. 7
      src/ImageSharp/Formats/WebP/Lossless/NearLosslessEnc.cs
  14. 60
      src/ImageSharp/Formats/WebP/Lossless/PixOrCopy.cs
  15. 18
      src/ImageSharp/Formats/WebP/Lossless/PredictorEncoder.cs
  16. 10
      src/ImageSharp/Formats/WebP/Lossless/Vp8LBackwardRefs.cs
  17. 2
      src/ImageSharp/Formats/WebP/Lossless/Vp8LBitEntropy.cs
  18. 54
      src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
  19. 14
      src/ImageSharp/Formats/WebP/Lossless/Vp8LHashChain.cs
  20. 4
      src/ImageSharp/Formats/WebP/Lossless/Vp8LHistogram.cs
  21. 51
      src/ImageSharp/Formats/WebP/Lossless/WebpLosslessDecoder.cs
  22. 18
      src/ImageSharp/Formats/WebP/Lossy/LossyUtils.cs
  23. 4
      src/ImageSharp/Formats/WebP/Lossy/PassStats.cs
  24. 8
      src/ImageSharp/Formats/WebP/Lossy/QuantEnc.cs
  25. 8
      src/ImageSharp/Formats/WebP/Lossy/Vp8Decoder.cs
  26. 16
      src/ImageSharp/Formats/WebP/Lossy/Vp8EncIterator.cs
  27. 2
      src/ImageSharp/Formats/WebP/Lossy/Vp8EncProba.cs
  28. 31
      src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs
  29. 89
      src/ImageSharp/Formats/WebP/Lossy/Vp8Encoding.cs
  30. 6
      src/ImageSharp/Formats/WebP/Lossy/Vp8Histogram.cs
  31. 2
      src/ImageSharp/Formats/WebP/Lossy/Vp8Matrix.cs
  32. 12
      src/ImageSharp/Formats/WebP/Lossy/Vp8Residual.cs
  33. 4
      src/ImageSharp/Formats/WebP/Lossy/Vp8SegmentInfo.cs
  34. 5
      src/ImageSharp/Formats/WebP/Lossy/Vp8StatsArray.cs
  35. 42
      src/ImageSharp/Formats/WebP/Lossy/WebpLossyDecoder.cs
  36. 4
      src/ImageSharp/Formats/WebP/Lossy/YuvConversion.cs
  37. 2
      src/ImageSharp/Formats/WebP/WebpConstants.cs
  38. 8
      src/ImageSharp/Formats/WebP/WebpDecoderCore.cs
  39. 5
      src/ImageSharp/Formats/WebP/WebpFeatures.cs
  40. 22
      src/ImageSharp/Formats/WebP/WebpImageFormatDetector.cs
  41. 6
      src/ImageSharp/Formats/WebP/WebpLookupTables.cs

13
src/ImageSharp/Formats/WebP/AlphaDecoder.cs

@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
if (this.Compressed == false)
{
Span<byte> dataSpan = this.Data.Memory.Span;
var pixelCount = this.Width * this.Height;
int pixelCount = this.Width * this.Height;
if (dataSpan.Length < pixelCount)
{
WebpThrowHelper.ThrowImageFormatException("not enough data in the ALPH chunk");
@ -222,8 +222,8 @@ namespace SixLabors.ImageSharp.Formats.Webp
{
// For vertical and gradient filtering, we need to decode the part above the
// cropTop row, in order to have the correct spatial predictors.
int topRow = (this.AlphaFilterType == WebpAlphaFilterType.None || this.AlphaFilterType == WebpAlphaFilterType.Horizontal) ? 0 : this.LastRow;
int firstRow = (this.LastRow < topRow) ? topRow : this.LastRow;
int topRow = this.AlphaFilterType == WebpAlphaFilterType.None || this.AlphaFilterType == WebpAlphaFilterType.Horizontal ? 0 : this.LastRow;
int firstRow = this.LastRow < topRow ? topRow : this.LastRow;
if (lastRow > firstRow)
{
// Special method for paletted alpha data.
@ -402,16 +402,13 @@ namespace SixLabors.ImageSharp.Formats.Webp
}
[MethodImpl(InliningOptions.ShortMethod)]
private static byte GetAlphaValue(int val)
{
return (byte)((val >> 8) & 0xff);
}
private static byte GetAlphaValue(int val) => (byte)((val >> 8) & 0xff);
[MethodImpl(InliningOptions.ShortMethod)]
private static int GradientPredictor(byte a, byte b, byte c)
{
int g = a + b - c;
return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit
return (g & ~0xff) == 0 ? g : g < 0 ? 0 : 255; // clip to 8bit.
}
[MethodImpl(InliningOptions.ShortMethod)]

2
src/ImageSharp/Formats/WebP/BitReader/Vp8BitReader.cs

@ -167,7 +167,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.BitReader
private void InitBitreader(uint size, int pos = 0)
{
var posPlusSize = pos + size;
long posPlusSize = pos + size;
this.range = 255 - 1;
this.value = 0;
this.bits = -8; // to load the very first 8 bits.

18
src/ImageSharp/Formats/WebP/BitWriter/Vp8BitWriter.cs

@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.BitWriter
tab = WebpConstants.Cat6;
}
var tabIdx = 0;
int tabIdx = 0;
while (mask != 0)
{
this.PutBit(v & mask, tab[tabIdx++]);
@ -192,7 +192,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.BitWriter
/// <param name="extraSize">The extra size in bytes needed.</param>
public override void BitWriterResize(int extraSize)
{
var neededSize = this.pos + extraSize;
long neededSize = this.pos + extraSize;
if (neededSize <= this.maxPos)
{
return;
@ -204,9 +204,9 @@ namespace SixLabors.ImageSharp.Formats.Webp.BitWriter
/// <inheritdoc/>
public override void Finish()
{
this.PutBits(0, 9 - this.nbBits);
this.nbBits = 0; // pad with zeroes.
this.Flush();
this.PutBits(0, 9 - this.nbBits);
this.nbBits = 0; // pad with zeroes.
this.Flush();
}
public void PutSegment(int s, Span<byte> p)
@ -352,7 +352,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.BitWriter
if (value < 0)
{
var valueToWrite = ((-value) << 1) | 1;
int valueToWrite = (-value << 1) | 1;
this.PutBits((uint)valueToWrite, nbBits + 1);
}
else
@ -377,7 +377,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.BitWriter
// overflow -> propagate carry over pending 0xff's
if (pos > 0)
{
this.Buffer[pos - 1]++;
this.Buffer[pos - 1]++;
}
}
@ -497,7 +497,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.BitWriter
{
for (int s = 0; s < 3; ++s)
{
if (bitWriter.PutBitUniform((proba.Segments[s] != 255) ? 1 : 0) != 0)
if (bitWriter.PutBitUniform(proba.Segments[s] != 255 ? 1 : 0) != 0)
{
bitWriter.PutBits(proba.Segments[s], 8);
}
@ -564,7 +564,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.BitWriter
if (bitWriter.PutBitUniform(probas.UseSkipProba ? 1 : 0) != 0)
{
bitWriter.PutBits(probas.SkipProba, 8);
bitWriter.PutBits(probas.SkipProba, 8);
}
}

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

@ -31,6 +31,6 @@ namespace SixLabors.ImageSharp.Formats.Webp
HistoPalette,
HistoTotal, // Must be last.
HistoTotal
}
}

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

@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
// Improve on simple LZ77 but only for high quality (TraceBackwards is costly).
if ((lz77TypeBest == (int)Vp8LLz77Type.Lz77Standard || lz77TypeBest == (int)Vp8LLz77Type.Lz77Box) && quality >= 25)
{
Vp8LHashChain hashChainTmp = (lz77TypeBest == (int)Vp8LLz77Type.Lz77Standard) ? hashChain : hashChainBox;
Vp8LHashChain hashChainTmp = lz77TypeBest == (int)Vp8LLz77Type.Lz77Standard ? hashChain : hashChainBox;
BackwardReferencesTraceBackwards(width, height, bgra, cacheBits, hashChainTmp, best, worst);
var histo = new Vp8LHistogram(worst, cacheBits);
double bitCostTrace = histo.EstimateBits();
@ -120,7 +120,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// <returns>Best cache size.</returns>
private static int CalculateBestCacheSize(ReadOnlySpan<uint> bgra, int quality, Vp8LBackwardRefs refs, int bestCacheBits)
{
int cacheBitsMax = (quality <= 25) ? 0 : bestCacheBits;
int cacheBitsMax = quality <= 25 ? 0 : bestCacheBits;
if (cacheBitsMax == 0)
{
// Local color cache is disabled.
@ -256,12 +256,12 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
int pixCount = xSize * ySize;
bool useColorCache = cacheBits > 0;
int literalArraySize = WebpConstants.NumLiteralCodes + WebpConstants.NumLengthCodes + ((cacheBits > 0) ? (1 << cacheBits) : 0);
int literalArraySize = WebpConstants.NumLiteralCodes + WebpConstants.NumLengthCodes + (cacheBits > 0 ? 1 << cacheBits : 0);
var costModel = new CostModel(literalArraySize);
int offsetPrev = -1;
int lenPrev = -1;
double offsetCost = -1;
int firstOffsetIsConstant = -1; // initialized with 'impossible' value
int firstOffsetIsConstant = -1; // initialized with 'impossible' value.
int reach = 0;
var colorCache = new ColorCache();
@ -273,8 +273,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
costModel.Build(xSize, cacheBits, refs);
var costManager = new CostManager(distArray, pixCount, costModel);
// We loop one pixel at a time, but store all currently best points to
// non-processed locations from this point.
// We loop one pixel at a time, but store all currently best points to non-processed locations from this point.
distArray[0] = 0;
// Add first pixel as literal.
@ -474,10 +473,10 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
int lenIni = len;
int maxReach = 0;
int jMax = (i + lenIni >= pixCount) ? pixCount - 1 : i + lenIni;
int jMax = i + lenIni >= pixCount ? pixCount - 1 : i + lenIni;
// Only start from what we have not checked already.
iLastCheck = (i > iLastCheck) ? i : iLastCheck;
iLastCheck = i > iLastCheck ? i : iLastCheck;
// We know the best match for the current pixel but we try to find the
// best matches for the current pixel AND the next one combined.
@ -640,7 +639,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
// Figure out if we should use the offset/length from the previous pixel
// as an initial guess and therefore only inspect the offsets in windowOffsetsNew[].
bool usePrev = (bestLengthPrev > 1) && (bestLengthPrev < MaxLength);
bool usePrev = bestLengthPrev > 1 && bestLengthPrev < MaxLength;
int numInd = usePrev ? windowOffsetsNewSize : windowOffsetsSize;
bestLength = usePrev ? bestLengthPrev - 1 : 0;
bestOffset = usePrev ? bestOffsetPrev : 0;
@ -663,7 +662,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int countsJ = counts[j];
if (countsJOffset != countsJ)
{
currLength += (countsJOffset < countsJ) ? countsJOffset : countsJ;
currLength += countsJOffset < countsJ ? countsJOffset : countsJ;
break;
}
@ -728,7 +727,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
int maxLen = LosslessUtils.MaxFindCopyLength(pixelCount - i);
int rleLen = LosslessUtils.FindMatchLength(bgra.Slice(i), bgra.Slice(i - 1), 0, maxLen);
int prevRowLen = (i < xSize) ? 0 : LosslessUtils.FindMatchLength(bgra.Slice(i), bgra.Slice(i - xSize), 0, maxLen);
int prevRowLen = i < xSize ? 0 : LosslessUtils.FindMatchLength(bgra.Slice(i), bgra.Slice(i - xSize), 0, maxLen);
if (rleLen >= prevRowLen && rleLen >= MinLength)
{
refs.Add(PixOrCopy.CreateCopy(1, (ushort)rleLen));

20
src/ImageSharp/Formats/WebP/Lossless/ColorCache.cs

@ -52,10 +52,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// </summary>
/// <param name="key">The key to lookup.</param>
/// <returns>The color for the key.</returns>
public uint Lookup(int key)
{
return this.Colors[key];
}
public uint Lookup(int key) => this.Colors[key];
/// <summary>
/// Returns the index of the given color.
@ -73,24 +70,15 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// </summary>
/// <param name="bgra">The color.</param>
/// <returns>The index for the color.</returns>
public int GetIndex(uint bgra)
{
return HashPix(bgra, this.HashShift);
}
public int GetIndex(uint bgra) => HashPix(bgra, this.HashShift);
/// <summary>
/// Adds a new color to the cache.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="bgra">The color to add.</param>
public void Set(uint key, uint bgra)
{
this.Colors[key] = bgra;
}
public void Set(uint key, uint bgra) => this.Colors[key] = bgra;
public static int HashPix(uint argb, int shift)
{
return (int)((argb * HashMul) >> shift);
}
public static int HashPix(uint argb, int shift) => (int)((argb * HashMul) >> shift);
}
}

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

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
public CostManager(ushort[] distArray, int pixCount, CostModel costModel)
{
int costCacheSize = (pixCount > BackwardReferenceEncoder.MaxLength) ? BackwardReferenceEncoder.MaxLength : pixCount;
int costCacheSize = pixCount > BackwardReferenceEncoder.MaxLength ? BackwardReferenceEncoder.MaxLength : pixCount;
this.CacheIntervals = new List<CostCacheInterval>();
this.CostCache = new List<double>();

5
src/ImageSharp/Formats/WebP/Lossless/CostModel.cs

@ -70,10 +70,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
return this.Literal[literalIdx];
}
public double GetLiteralCost(uint v)
{
return this.Alpha[v >> 24] + this.Red[(v >> 16) & 0xff] + this.Literal[(v >> 8) & 0xff] + this.Blue[v & 0xff];
}
public double GetLiteralCost(uint v) => this.Alpha[v >> 24] + this.Red[(v >> 16) & 0xff] + this.Literal[(v >> 8) & 0xff] + this.Blue[v & 0xff];
private static void ConvertPopulationCountTableToBitEstimates(int numSymbols, uint[] populationCounts, double[] output)
{

34
src/ImageSharp/Formats/WebP/Lossless/HistogramEncoder.cs

@ -35,8 +35,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int histoYSize = histoBits > 0 ? LosslessUtils.SubSampleSize(ySize, histoBits) : 1;
int imageHistoRawSize = histoXSize * histoYSize;
int entropyCombineNumBins = BinSize;
var mapTmp = new ushort[imageHistoRawSize];
var clusterMappings = new ushort[imageHistoRawSize];
ushort[] mapTmp = new ushort[imageHistoRawSize];
ushort[] clusterMappings = new ushort[imageHistoRawSize];
var origHisto = new List<Vp8LHistogram>(imageHistoRawSize);
for (int i = 0; i < imageHistoRawSize; i++)
{
@ -49,11 +49,11 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
// Copies the histograms and computes its bitCost. histogramSymbols is optimized.
int numUsed = HistogramCopyAndAnalyze(origHisto, imageHisto, histogramSymbols);
var entropyCombine = (numUsed > entropyCombineNumBins * 2) && (quality < 100);
bool entropyCombine = numUsed > entropyCombineNumBins * 2 && quality < 100;
if (entropyCombine)
{
ushort[] binMap = mapTmp;
var numClusters = numUsed;
int numClusters = numUsed;
double combineCostFactor = GetCombineCostFactor(imageHistoRawSize, quality);
HistogramAnalyzeEntropyBin(imageHisto, binMap);
@ -218,7 +218,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
// For some images, 'tryCombine' turns out to be false for a lot of
// histogram pairs. In that case, we fallback to combining
// histograms as usual to avoid increasing the header size.
bool tryCombine = (curCombo.TrivialSymbol != NonTrivialSym) || ((histograms[idx].TrivialSymbol == NonTrivialSym) && (histograms[first].TrivialSymbol == NonTrivialSym));
bool tryCombine = curCombo.TrivialSymbol != NonTrivialSym || (histograms[idx].TrivialSymbol == NonTrivialSym && histograms[first].TrivialSymbol == NonTrivialSym);
int maxCombineFailures = 32;
if (tryCombine || binInfo[binId].NumCombineFailures >= maxCombineFailures)
{
@ -275,7 +275,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
// Create a mapping from a cluster id to its minimal version.
var clusterMax = 0;
int clusterMax = 0;
clusterMappingsTmp.AsSpan().Fill(0);
// Re-map the ids.
@ -305,7 +305,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
uint seed = 1;
int triesWithNoSuccess = 0;
var numUsed = histograms.Count(h => h != null);
int numUsed = histograms.Count(h => h != null);
int outerIters = numUsed;
int numTriesNoSuccess = outerIters / 2;
@ -320,7 +320,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int maxSize = 9;
// Fill the initial mapping.
var mappings = new int[histograms.Count];
int[] mappings = new int[histograms.Count];
for (int j = 0, iter = 0; iter < histograms.Count; iter++)
{
if (histograms[iter] == null)
@ -334,7 +334,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
// Collapse similar histograms.
for (int iter = 0; iter < outerIters && numUsed >= minClusterSize && ++triesWithNoSuccess < numTriesNoSuccess; iter++)
{
double bestCost = (histoPriorityList.Count == 0) ? 0.0d : histoPriorityList[0].CostDiff;
double bestCost = histoPriorityList.Count == 0 ? 0.0d : histoPriorityList[0].CostDiff;
int numTries = numUsed / 2;
uint randRange = (uint)((numUsed - 1) * numUsed);
@ -354,7 +354,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
idx2 = mappings[idx2];
// Calculate cost reduction on combination.
var currCost = HistoPriorityListPush(histoPriorityList, maxSize, histograms, idx1, idx2, bestCost);
double currCost = HistoPriorityListPush(histoPriorityList, maxSize, histograms, idx1, idx2, bestCost);
// Found a better pair?
if (currCost < 0)
@ -374,10 +374,10 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
// Get the best histograms.
var bestIdx1 = histoPriorityList[0].Idx1;
var bestIdx2 = histoPriorityList[0].Idx2;
int bestIdx1 = histoPriorityList[0].Idx1;
int bestIdx2 = histoPriorityList[0].Idx2;
var mappingIndex = Array.IndexOf(mappings, bestIdx2);
int mappingIndex = Array.IndexOf(mappings, bestIdx2);
Span<int> src = mappings.AsSpan(mappingIndex + 1, numUsed - mappingIndex - 1);
Span<int> dst = mappings.AsSpan(mappingIndex);
src.CopyTo(dst);
@ -554,7 +554,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
// Recompute each output.
var paletteCodeBits = output.First().PaletteCodeBits;
int paletteCodeBits = output.First().PaletteCodeBits;
output.Clear();
for (int i = 0; i < outSize; i++)
{
@ -620,7 +620,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
double sumCost = h1.BitCost + h2.BitCost;
pair.CostCombo = 0.0d;
h1.GetCombinedHistogramEntropy(h2, sumCost + threshold, costInitial: pair.CostCombo, out var cost);
h1.GetCombinedHistogramEntropy(h2, sumCost + threshold, costInitial: pair.CostCombo, out double cost);
pair.CostCombo = cost;
pair.CostDiff = pair.CostCombo - sumCost;
}
@ -633,7 +633,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
if (pair.CostDiff < histoList[0].CostDiff)
{
// Replace the best pair.
var oldIdx = histoList.IndexOf(pair);
int oldIdx = histoList.IndexOf(pair);
histoList[oldIdx] = histoList[0];
histoList[0] = pair;
}
@ -642,7 +642,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
private static void HistogramAdd(Vp8LHistogram a, Vp8LHistogram b, Vp8LHistogram output)
{
a.Add(b, output);
output.TrivialSymbol = (a.TrivialSymbol == b.TrivialSymbol) ? a.TrivialSymbol : NonTrivialSym;
output.TrivialSymbol = a.TrivialSymbol == b.TrivialSymbol ? a.TrivialSymbol : NonTrivialSym;
}
private static double GetCombineCostFactor(int histoSize, int quality)

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

@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
else
{
return (t1.Value < t2.Value) ? -1 : 1;
return t1.Value < t2.Value ? -1 : 1;
}
}

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

@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
uint sum = 0;
for (int i = 0; i < length + 1; ++i)
{
var valuesShouldBeCollapsedToStrideAverage = ValuesShouldBeCollapsedToStrideAverage((int)counts[i], (int)limit);
bool valuesShouldBeCollapsedToStrideAverage = ValuesShouldBeCollapsedToStrideAverage((int)counts[i], (int)limit);
if (i == length || goodForRle[i] || (i != 0 && goodForRle[i - 1]) || !valuesShouldBeCollapsedToStrideAverage)
{
if (stride >= 4 || (stride >= 3 && sum == 0))
@ -193,7 +193,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
if (histogram[j] != 0)
{
uint count = (histogram[j] < countMin) ? countMin : histogram[j];
uint count = histogram[j] < countMin ? countMin : histogram[j];
tree[idx].TotalCount = (int)count;
tree[idx].Value = j;
tree[idx].PoolIndexLeft = -1;
@ -229,9 +229,9 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
}
var endIdx = k + 1;
var num = treeSize - k;
var startIdx = endIdx + num - 1;
int endIdx = k + 1;
int num = treeSize - k;
int startIdx = endIdx + num - 1;
for (int i = startIdx; i >= endIdx; i--)
{
tree[i] = (HuffmanTree)tree[i - 1].DeepClone();
@ -241,7 +241,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
tree[k].Value = -1;
tree[k].PoolIndexLeft = treePoolSize - 1;
tree[k].PoolIndexRight = treePoolSize - 2;
treeSize = treeSize + 1;
treeSize++;
}
SetBitDepths(tree, treePool, bitDepths, 0);
@ -284,7 +284,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
k++;
}
var runs = k - i;
int runs = k - i;
if (value == 0)
{
tokenPos += CodeRepeatedZeros(runs, tokensArray.AsSpan(tokenPos));
@ -308,17 +308,17 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
Guard.MustBeGreaterThan(codeLengthsSize, 0, nameof(codeLengthsSize));
// sorted[codeLengthsSize] is a pre-allocated array for sorting symbols by code length.
var sorted = new int[codeLengthsSize];
int[] sorted = new int[codeLengthsSize];
int totalSize = 1 << rootBits; // total size root table + 2nd level table.
int len; // current code length.
int symbol; // symbol index in original or sorted table.
var counts = new int[WebpConstants.MaxAllowedCodeLength + 1]; // number of codes of each length.
var offsets = new int[WebpConstants.MaxAllowedCodeLength + 1]; // offsets in sorted table for each length.
int[] counts = new int[WebpConstants.MaxAllowedCodeLength + 1]; // number of codes of each length.
int[] offsets = new int[WebpConstants.MaxAllowedCodeLength + 1]; // offsets in sorted table for each length.
// Build histogram of code lengths.
for (symbol = 0; symbol < codeLengthsSize; ++symbol)
{
var codeLengthOfSymbol = codeLengths[symbol];
int codeLengthOfSymbol = codeLengths[symbol];
if (codeLengthOfSymbol > WebpConstants.MaxAllowedCodeLength)
{
return 0;
@ -338,7 +338,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
for (len = 1; len < WebpConstants.MaxAllowedCodeLength; ++len)
{
int codesOfLength = counts[len];
if (codesOfLength > (1 << len))
if (codesOfLength > 1 << len)
{
return 0;
}
@ -381,7 +381,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
// Fill in root table.
for (len = 1, step = 2; len <= rootBits; ++len, step <<= 1)
{
var countsLen = counts[len];
int countsLen = counts[len];
numOpen <<= 1;
numNodes += numOpen;
numOpen -= counts[len];
@ -652,9 +652,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// <summary>
/// Heuristics for selecting the stride ranges to collapse.
/// </summary>
private static bool ValuesShouldBeCollapsedToStrideAverage(int a, int b)
{
return Math.Abs(a - b) < 4;
}
private static bool ValuesShouldBeCollapsedToStrideAverage(int a, int b) => Math.Abs(a - b) < 4;
}
}

38
src/ImageSharp/Formats/WebP/Lossless/LosslessUtils.cs

@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
[MethodImpl(InliningOptions.ShortMethod)]
public static int MaxFindCopyLength(int len) => (len < BackwardReferenceEncoder.MaxLength) ? len : BackwardReferenceEncoder.MaxLength;
public static int MaxFindCopyLength(int len) => len < BackwardReferenceEncoder.MaxLength ? len : BackwardReferenceEncoder.MaxLength;
public static int PrefixEncodeBits(int distance, ref int extraBits)
{
@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int i;
for (i = 0; i + 8 <= numPixels; i += 8)
{
var idx = p + i;
uint* idx = p + i;
Vector256<byte> input = Avx.LoadVector256((ushort*)idx).AsByte();
Vector256<byte> in0g0g = Avx2.Shuffle(input, mask);
Vector256<byte> output = Avx2.Add(input, in0g0g);
@ -131,7 +131,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int i;
for (i = 0; i + 4 <= numPixels; i += 4)
{
var idx = p + i;
uint* idx = p + i;
Vector128<byte> input = Sse2.LoadVector128((ushort*)idx).AsByte();
Vector128<byte> in0g0g = Ssse3.Shuffle(input, mask);
Vector128<byte> output = Sse2.Add(input, in0g0g);
@ -146,14 +146,14 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
else if (Sse2.IsSupported)
{
var mask = SimdUtils.Shuffle.MmShuffle(2, 2, 0, 0);
byte mask = SimdUtils.Shuffle.MmShuffle(2, 2, 0, 0);
int numPixels = pixelData.Length;
fixed (uint* p = pixelData)
{
int i;
for (i = 0; i + 4 <= numPixels; i += 4)
{
var idx = p + i;
uint* idx = p + i;
Vector128<ushort> input = Sse2.LoadVector128((ushort*)idx);
Vector128<ushort> a = Sse2.ShiftRightLogical(input.AsUInt16(), 8); // 0 a 0 g
Vector128<ushort> b = Sse2.ShuffleLow(a, mask);
@ -201,7 +201,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int i;
for (i = 0; i + 8 <= numPixels; i += 8)
{
var idx = p + i;
uint* idx = p + i;
Vector256<byte> input = Avx.LoadVector256((ushort*)idx).AsByte();
Vector256<byte> in0g0g = Avx2.Shuffle(input, mask);
Vector256<byte> output = Avx2.Subtract(input, in0g0g);
@ -223,7 +223,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int i;
for (i = 0; i + 4 <= numPixels; i += 4)
{
var idx = p + i;
uint* idx = p + i;
Vector128<byte> input = Sse2.LoadVector128((ushort*)idx).AsByte();
Vector128<byte> in0g0g = Ssse3.Shuffle(input, mask);
Vector128<byte> output = Sse2.Subtract(input, in0g0g);
@ -238,14 +238,14 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
else if (Sse2.IsSupported)
{
var mask = SimdUtils.Shuffle.MmShuffle(2, 2, 0, 0);
byte mask = SimdUtils.Shuffle.MmShuffle(2, 2, 0, 0);
int numPixels = pixelData.Length;
fixed (uint* p = pixelData)
{
int i;
for (i = 0; i + 4 <= numPixels; i += 4)
{
var idx = p + i;
uint* idx = p + i;
Vector128<ushort> input = Sse2.LoadVector128((ushort*)idx);
Vector128<ushort> a = Sse2.ShiftRightLogical(input.AsUInt16(), 8); // 0 a 0 g
Vector128<ushort> b = Sse2.ShuffleLow(a, mask);
@ -299,7 +299,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int countMask = pixelsPerByte - 1;
int bitMask = (1 << bitsPerPixel) - 1;
var decodedPixelData = new uint[width * height];
uint[] decodedPixelData = new uint[width * height];
int pixelDataPos = 0;
for (int y = 0; y < height; ++y)
{
@ -401,13 +401,13 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
Vector128<int> multsb2 = MkCst16(Cst5b(m.RedToBlue), 0);
var maskalphagreen = Vector128.Create(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255);
var maskredblue = Vector128.Create(255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0);
var shufflemask = SimdUtils.Shuffle.MmShuffle(2, 2, 0, 0);
byte shufflemask = SimdUtils.Shuffle.MmShuffle(2, 2, 0, 0);
int idx;
fixed (uint* src = data)
{
for (idx = 0; idx + 4 <= numPixels; idx += 4)
{
var pos = src + idx;
uint* pos = src + idx;
Vector128<uint> input = Sse2.LoadVector128(pos);
Vector128<byte> a = Sse2.And(input.AsByte(), maskalphagreen);
Vector128<short> b = Sse2.ShuffleLow(a.AsInt16(), shufflemask);
@ -466,13 +466,13 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
Vector128<int> multsrb = MkCst16(Cst5b(m.GreenToRed), Cst5b(m.GreenToBlue));
Vector128<int> multsb2 = MkCst16(Cst5b(m.RedToBlue), 0);
var maskalphagreen = Vector128.Create(0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255);
var shufflemask = SimdUtils.Shuffle.MmShuffle(2, 2, 0, 0);
byte shufflemask = SimdUtils.Shuffle.MmShuffle(2, 2, 0, 0);
fixed (uint* src = pixelData)
{
int idx;
for (idx = 0; idx + 4 <= pixelData.Length; idx += 4)
{
var pos = src + idx;
uint* pos = src + idx;
Vector128<uint> input = Sse2.LoadVector128(pos);
Vector128<byte> a = Sse2.And(input.AsByte(), maskalphagreen);
Vector128<short> b = Sse2.ShuffleLow(a.AsInt16(), shufflemask);
@ -754,13 +754,13 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// <summary>
/// Fast calculation of log2(v) for integer input.
/// </summary>
public static float FastLog2(uint v) => (v < LogLookupIdxMax) ? WebpLookupTables.Log2Table[v] : FastLog2Slow(v);
public static float FastLog2(uint v) => v < LogLookupIdxMax ? WebpLookupTables.Log2Table[v] : FastLog2Slow(v);
/// <summary>
/// Fast calculation of v * log2(v) for integer input.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static float FastSLog2(uint v) => (v < LogLookupIdxMax) ? WebpLookupTables.SLog2Table[v] : FastSLog2Slow(v);
public static float FastSLog2(uint v) => v < LogLookupIdxMax ? WebpLookupTables.SLog2Table[v] : FastSLog2Slow(v);
[MethodImpl(InliningOptions.ShortMethod)]
public static void ColorCodeToMultipliers(uint colorCode, ref Vp8LMultipliers m)
@ -803,7 +803,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
// The correction factor: log(1 + d) ~ d; for very small d values, so
// log2(1 + (v % y) / v) ~ LOG_2_RECIPROCAL * (v % y)/v
// LOG_2_RECIPROCAL ~ 23/16
var correction = (int)((23 * (origV & (y - 1))) >> 4);
int correction = (int)((23 * (origV & (y - 1))) >> 4);
return (vF * (WebpLookupTables.Log2Table[v] + logCnt)) + correction;
}
else
@ -855,7 +855,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int highestBit = WebpCommonUtils.BitsLog2Floor((uint)--distance);
int secondHighestBit = (distance >> (highestBit - 1)) & 1;
extraBits = highestBit - 1;
var code = (2 * highestBit) + secondHighestBit;
int code = (2 * highestBit) + secondHighestBit;
return code;
}
@ -1252,7 +1252,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
Sub3((int)((a >> 16) & 0xff), (int)((b >> 16) & 0xff), (int)((c >> 16) & 0xff)) +
Sub3((int)((a >> 8) & 0xff), (int)((b >> 8) & 0xff), (int)((c >> 8) & 0xff)) +
Sub3((int)(a & 0xff), (int)(b & 0xff), (int)(c & 0xff));
return (paMinusPb <= 0) ? a : b;
return paMinusPb <= 0 ? a : b;
}
[MethodImpl(InliningOptions.ShortMethod)]

7
src/ImageSharp/Formats/WebP/Lossless/NearLosslessEnc.cs

@ -102,14 +102,11 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossless
return biased & ~mask;
}
private static bool IsSmooth(Span<uint> prevRow, Span<uint> currRow, Span<uint> nextRow, int ix, int limit)
{
// Check that all pixels in 4-connected neighborhood are smooth.
return IsNear(currRow[ix], currRow[ix - 1], limit) &&
private static bool IsSmooth(Span<uint> prevRow, Span<uint> currRow, Span<uint> nextRow, int ix, int limit) =>
IsNear(currRow[ix], currRow[ix - 1], limit) && // Check that all pixels in 4-connected neighborhood are smooth.
IsNear(currRow[ix], currRow[ix + 1], limit) &&
IsNear(currRow[ix], prevRow[ix], limit) &&
IsNear(currRow[ix], nextRow[ix], limit);
}
// Checks if distance between corresponding channel values of pixels a and b is within the given limit.
private static bool IsNear(uint a, uint b, int limit)

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

@ -14,69 +14,41 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
public uint BgraOrDistance { get; set; }
public static PixOrCopy CreateCacheIdx(int idx)
{
return new PixOrCopy()
public static PixOrCopy CreateCacheIdx(int idx) =>
new PixOrCopy()
{
Mode = PixOrCopyMode.CacheIdx,
BgraOrDistance = (uint)idx,
Len = 1
};
}
public static PixOrCopy CreateLiteral(uint bgra)
{
return new PixOrCopy()
public static PixOrCopy CreateLiteral(uint bgra) =>
new PixOrCopy()
{
Mode = PixOrCopyMode.Literal,
BgraOrDistance = bgra,
Len = 1
};
}
public static PixOrCopy CreateCopy(uint distance, ushort len)
public static PixOrCopy CreateCopy(uint distance, ushort len) => new PixOrCopy()
{
return new PixOrCopy()
{
Mode = PixOrCopyMode.Copy,
BgraOrDistance = distance,
Len = len
};
}
Mode = PixOrCopyMode.Copy,
BgraOrDistance = distance,
Len = len
};
public uint Literal(int component)
{
return (this.BgraOrDistance >> (component * 8)) & 0xff;
}
public uint Literal(int component) => (this.BgraOrDistance >> (component * 8)) & 0xff;
public uint CacheIdx()
{
return this.BgraOrDistance;
}
public uint CacheIdx() => this.BgraOrDistance;
public ushort Length()
{
return this.Len;
}
public ushort Length() => this.Len;
public uint Distance()
{
return this.BgraOrDistance;
}
public uint Distance() => this.BgraOrDistance;
public bool IsLiteral()
{
return this.Mode == PixOrCopyMode.Literal;
}
public bool IsLiteral() => this.Mode == PixOrCopyMode.Literal;
public bool IsCacheIdx()
{
return this.Mode == PixOrCopyMode.CacheIdx;
}
public bool IsCacheIdx() => this.Mode == PixOrCopyMode.CacheIdx;
public bool IsCopy()
{
return this.Mode == PixOrCopyMode.Copy;
}
public bool IsCopy() => this.Mode == PixOrCopyMode.Copy;
}
}

18
src/ImageSharp/Formats/WebP/Lossless/PredictorEncoder.cs

@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int maxQuantization = 1 << LosslessUtils.NearLosslessBits(nearLosslessQuality);
// TODO: Can we optimize this?
var histo = new int[4][];
int[][] histo = new int[4][];
for (int i = 0; i < 4; i++)
{
histo[i] = new int[256];
@ -202,7 +202,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int maxX = GetMin(tileSize, width - startX);
// Whether there exist columns just outside the tile.
int haveLeft = (startX > 0) ? 1 : 0;
int haveLeft = startX > 0 ? 1 : 0;
// Position and size of the strip covering the tile and adjacent columns if they exist.
int contextStartX = startX - haveLeft;
@ -210,8 +210,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int tilesPerRow = LosslessUtils.SubSampleSize(width, bits);
// Prediction modes of the left and above neighbor tiles.
int leftMode = (int)((tileX > 0) ? (modes[(tileY * tilesPerRow) + tileX - 1] >> 8) & 0xff : 0xff);
int aboveMode = (int)((tileY > 0) ? (modes[((tileY - 1) * tilesPerRow) + tileX] >> 8) & 0xff : 0xff);
int leftMode = (int)(tileX > 0 ? (modes[(tileY * tilesPerRow) + tileX - 1] >> 8) & 0xff : 0xff);
int aboveMode = (int)(tileY > 0 ? (modes[((tileY - 1) * tilesPerRow) + tileX] >> 8) & 0xff : 0xff);
// The width of upper_row and current_row is one pixel larger than image width
// to allow the top right pixel to point to the leftmost pixel of the next row
@ -260,7 +260,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
// the image (wrapping to the leftmost pixel of the next row if it does
// not exist in the currentRow).
int offset = (y * width) + contextStartX;
Span<uint> src = argb.Slice(offset, maxX + haveLeft + ((y + 1) < height ? 1 : 0));
Span<uint> src = argb.Slice(offset, maxX + haveLeft + (y + 1 < height ? 1 : 0));
Span<uint> dst = currentRow.Slice(contextStartX);
src.CopyTo(dst);
@ -350,7 +350,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
uint residual;
if (y == 0)
{
predict = (x == 0) ? WebpConstants.ArgbBlack : currentRow[x - 1]; // Left.
predict = x == 0 ? WebpConstants.ArgbBlack : currentRow[x - 1]; // Left.
}
else if (x == 0)
{
@ -478,7 +478,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
quantization >>= 1;
}
if ((value >> 24) == 0 || (value >> 24) == 0xff)
if (value >> 24 == 0 || value >> 24 == 0xff)
{
// Preserve transparency of fully transparent or fully opaque pixels.
a = NearLosslessDiff((byte)((value >> 24) & 0xff), (byte)((predict >> 24) & 0xff));
@ -586,7 +586,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
Span<uint> tmp32 = upperRow;
upperRow = currentRow;
currentRow = tmp32;
Span<uint> src = argb.Slice(y * width, width + ((y + 1) < height ? 1 : 0));
Span<uint> src = argb.Slice(y * width, width + (y + 1 < height ? 1 : 0));
src.CopyTo(currentRow);
if (lowEffort)
@ -1165,7 +1165,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
private static uint MultipliersToColorCode(Vp8LMultipliers m) => 0xff000000u | ((uint)m.RedToBlue << 16) | ((uint)m.GreenToBlue << 8) | m.GreenToRed;
[MethodImpl(InliningOptions.ShortMethod)]
private static int GetMin(int a, int b) => (a > b) ? b : a;
private static int GetMin(int a, int b) => a > b ? b : a;
[MethodImpl(InliningOptions.ShortMethod)]
private static int GetMax(int a, int b) => (a < b) ? b : a;

10
src/ImageSharp/Formats/WebP/Lossless/Vp8LBackwardRefs.cs

@ -7,10 +7,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
internal class Vp8LBackwardRefs
{
public Vp8LBackwardRefs()
{
this.Refs = new List<PixOrCopy>();
}
public Vp8LBackwardRefs() => this.Refs = new List<PixOrCopy>();
/// <summary>
/// Gets or sets the common block-size.
@ -22,9 +19,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// </summary>
public List<PixOrCopy> Refs { get; }
public void Add(PixOrCopy pixOrCopy)
{
this.Refs.Add(pixOrCopy);
}
public void Add(PixOrCopy pixOrCopy) => this.Refs.Add(pixOrCopy);
}
}

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

@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
double minLimit = (2 * this.Sum) - this.MaxVal;
minLimit = (mix * minLimit) + ((1.0 - mix) * this.Entropy);
return (this.Entropy < minLimit) ? minLimit : this.Entropy;
return this.Entropy < minLimit ? minLimit : this.Entropy;
}
public void BitsEntropyUnrefined(Span<uint> array, int n)

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

@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
this.Refs[i] = new Vp8LBackwardRefs
{
BlockSize = (refsBlockSize < MinBlockSize) ? MinBlockSize : refsBlockSize
BlockSize = refsBlockSize < MinBlockSize ? MinBlockSize : refsBlockSize
};
}
}
@ -283,10 +283,10 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
bool useCache = true;
this.UsePalette = crunchConfig.EntropyIdx == EntropyIx.Palette ||
crunchConfig.EntropyIdx == EntropyIx.PaletteAndSpatial;
this.UseSubtractGreenTransform = (crunchConfig.EntropyIdx == EntropyIx.SubGreen) ||
(crunchConfig.EntropyIdx == EntropyIx.SpatialSubGreen);
this.UsePredictorTransform = (crunchConfig.EntropyIdx == EntropyIx.Spatial) ||
(crunchConfig.EntropyIdx == EntropyIx.SpatialSubGreen);
this.UseSubtractGreenTransform = crunchConfig.EntropyIdx == EntropyIx.SubGreen ||
crunchConfig.EntropyIdx == EntropyIx.SpatialSubGreen;
this.UsePredictorTransform = crunchConfig.EntropyIdx == EntropyIx.Spatial ||
crunchConfig.EntropyIdx == EntropyIx.SpatialSubGreen;
if (lowEffort)
{
this.UseCrossColorTransform = false;
@ -305,7 +305,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
if (this.nearLossless)
{
// Apply near-lossless preprocessing.
bool useNearLossless = (this.nearLosslessQuality < 100) && !this.UsePalette && !this.UsePredictorTransform;
bool useNearLossless = this.nearLosslessQuality < 100 && !this.UsePalette && !this.UsePredictorTransform;
if (useNearLossless)
{
this.AllocateTransformBuffer(width, height);
@ -320,7 +320,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
this.MapImageFromPalette(width, height);
// If using a color cache, do not have it bigger than the number of colors.
if (useCache && this.PaletteSize < (1 << WebpConstants.MaxColorCacheBits))
if (useCache && this.PaletteSize < 1 << WebpConstants.MaxColorCacheBits)
{
this.CacheBits = WebpCommonUtils.BitsLog2Floor((uint)this.PaletteSize) + 1;
}
@ -419,7 +419,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
this.TransformBits = GetTransformBits(this.method, this.HistoBits);
// Try out multiple LZ77 on images with few colors.
int nlz77s = (this.PaletteSize > 0 && this.PaletteSize <= 16) ? 2 : 1;
int nlz77s = this.PaletteSize > 0 && this.PaletteSize <= 16 ? 2 : 1;
EntropyIx entropyIdx = this.AnalyzeEntropy(bgra, width, height, usePalette, this.PaletteSize, this.TransformBits, out redAndBlueAlwaysZero);
bool doNotCache = false;
@ -463,7 +463,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
crunchConfig.SubConfigs.Add(new CrunchSubConfig
{
Lz77 = (j == 0) ? (int)Vp8LLz77Type.Lz77Standard | (int)Vp8LLz77Type.Lz77Rle : (int)Vp8LLz77Type.Lz77Box,
Lz77 = j == 0 ? (int)Vp8LLz77Type.Lz77Standard | (int)Vp8LLz77Type.Lz77Rle : (int)Vp8LLz77Type.Lz77Box,
DoNotCache = doNotCache
});
}
@ -944,7 +944,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
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);
int tileMask = histoBits == 0 ? 0 : -(1 << histoBits);
// x and y trace the position in the image.
int x = 0;
@ -957,7 +957,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
while (c.MoveNext())
{
PixOrCopy v = c.Current;
if ((tileX != (x & tileMask)) || (tileY != (y & tileMask)))
if (tileX != (x & tileMask) || tileY != (y & tileMask))
{
tileX = x & tileMask;
tileY = y & tileMask;
@ -1038,7 +1038,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
uint pix = currentRow[x];
uint pixDiff = LosslessUtils.SubPixels(pix, pixPrev);
pixPrev = pix;
if ((pixDiff == 0) || (prevRow != null && pix == prevRow[x]))
if (pixDiff == 0 || (prevRow != null && pix == prevRow[x]))
{
continue;
}
@ -1245,11 +1245,11 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
// This is done line by line.
if (paletteSize <= 4)
{
xBits = (paletteSize <= 2) ? 3 : 2;
xBits = paletteSize <= 2 ? 3 : 2;
}
else
{
xBits = (paletteSize <= 16) ? 1 : 0;
xBits = paletteSize <= 16 ? 1 : 0;
}
this.CurrentWidth = LosslessUtils.SubSampleSize(width, xBits);
@ -1495,17 +1495,17 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
byte bd = (byte)((diff >> 0) & 0xff);
if (rd != 0x00)
{
signFound |= (byte)((rd < 0x80) ? 1 : 2);
signFound |= (byte)(rd < 0x80 ? 1 : 2);
}
if (gd != 0x00)
{
signFound |= (byte)((gd < 0x80) ? 8 : 16);
signFound |= (byte)(gd < 0x80 ? 8 : 16);
}
if (bd != 0x00)
{
signFound |= (byte)((bd < 0x80) ? 64 : 128);
signFound |= (byte)(bd < 0x80 ? 64 : 128);
}
}
@ -1555,8 +1555,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
for (int k = 0; k < 5; k++)
{
int numSymbols =
(k == 0) ? histo.NumCodes() :
(k == 4) ? WebpConstants.NumDistanceCodes : 256;
k == 0 ? histo.NumCodes() :
k == 4 ? WebpConstants.NumDistanceCodes : 256;
huffmanCodes[startIdx + k].NumSymbols = numSymbols;
}
}
@ -1631,8 +1631,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
histoBits++;
}
return (histoBits < WebpConstants.MinHuffmanBits) ? WebpConstants.MinHuffmanBits :
(histoBits > WebpConstants.MaxHuffmanBits) ? WebpConstants.MaxHuffmanBits : histoBits;
return histoBits < WebpConstants.MinHuffmanBits ? WebpConstants.MinHuffmanBits :
histoBits > WebpConstants.MaxHuffmanBits ? WebpConstants.MaxHuffmanBits : histoBits;
}
/// <summary>
@ -1681,8 +1681,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
[MethodImpl(InliningOptions.ShortMethod)]
private static int GetTransformBits(int method, int histoBits)
{
int maxTransformBits = (method < 4) ? 6 : (method > 4) ? 4 : 5;
int res = (histoBits > maxTransformBits) ? maxTransformBits : histoBits;
int maxTransformBits = method < 4 ? 6 : method > 4 ? 4 : 5;
int res = histoBits > maxTransformBits ? maxTransformBits : histoBits;
return res;
}
@ -1728,10 +1728,10 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
private static uint ApplyPaletteHash0(uint color) => (color >> 8) & 0xff; // Focus on the green color.
[MethodImpl(InliningOptions.ShortMethod)]
private static uint ApplyPaletteHash1(uint color) => ((uint)((color & 0x00ffffffu) * 4222244071ul)) >> (32 - PaletteInvSizeBits); // Forget about alpha.
private static uint ApplyPaletteHash1(uint color) => (uint)((color & 0x00ffffffu) * 4222244071ul) >> (32 - PaletteInvSizeBits); // Forget about alpha.
[MethodImpl(InliningOptions.ShortMethod)]
private static uint ApplyPaletteHash2(uint color) => ((uint)((color & 0x00ffffffu) * ((1ul << 31) - 1))) >> (32 - PaletteInvSizeBits); // Forget about alpha.
private static uint ApplyPaletteHash2(uint color) => (uint)((color & 0x00ffffffu) * ((1ul << 31) - 1)) >> (32 - PaletteInvSizeBits); // Forget about alpha.
// Note that masking with 0xffffffffu is for preventing an
// 'unsigned int overflow' warning. Doesn't impact the compiled code.
@ -1739,7 +1739,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
private static uint HashPix(uint pix) => (uint)((((long)pix + (pix >> 19)) * 0x39c5fba7L) & 0xffffffffu) >> 24;
[MethodImpl(InliningOptions.ShortMethod)]
private static int PaletteCompareColorsForSort(uint p1, uint p2) => (p1 < p2) ? -1 : 1;
private static int PaletteCompareColorsForSort(uint p1, uint p2) => p1 < p2 ? -1 : 1;
[MethodImpl(InliningOptions.ShortMethod)]
private static uint PaletteComponentDistance(uint v) => (v <= 128) ? v : (256 - v);
@ -1749,7 +1749,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
// VP8LResidualImage needs room for 2 scanlines of uint32 pixels with an extra
// pixel in each, plus 2 regular scanlines of bytes.
int bgraScratchSize = this.UsePredictorTransform ? ((width + 1) * 2) + (((width * 2) + 4 - 1) / 4) : 0;
int transformDataSize = (this.UsePredictorTransform || this.UseCrossColorTransform) ? LosslessUtils.SubSampleSize(width, this.TransformBits) * LosslessUtils.SubSampleSize(height, this.TransformBits) : 0;
int transformDataSize = this.UsePredictorTransform || this.UseCrossColorTransform ? LosslessUtils.SubSampleSize(width, this.TransformBits) * LosslessUtils.SubSampleSize(height, this.TransformBits) : 0;
this.BgraScratch = this.memoryAllocator.Allocate<uint>(bgraScratchSize);
this.TransformData = this.memoryAllocator.Allocate<uint>(transformDataSize);

14
src/ImageSharp/Formats/WebP/Lossless/Vp8LHashChain.cs

@ -142,8 +142,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int iter = iterMax;
int bestLength = 0;
uint bestDistance = 0;
int minPos = (basePosition > windowSize) ? basePosition - windowSize : 0;
int lengthMax = (maxLen < 256) ? maxLen : 256;
int minPos = basePosition > windowSize ? basePosition - windowSize : 0;
int lengthMax = maxLen < 256 ? maxLen : 256;
pos = chain[basePosition];
int currLength;
@ -273,12 +273,12 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
[MethodImpl(InliningOptions.ShortMethod)]
private static int GetWindowSizeForHashChain(int quality, int xSize)
{
int maxWindowSize = (quality > 75) ? WindowSize
: (quality > 50) ? (xSize << 8)
: (quality > 25) ? (xSize << 6)
: (xSize << 4);
int maxWindowSize = quality > 75 ? WindowSize
: quality > 50 ? xSize << 8
: quality > 25 ? xSize << 6
: xSize << 4;
return (maxWindowSize > WindowSize) ? WindowSize : maxWindowSize;
return maxWindowSize > WindowSize ? WindowSize : maxWindowSize;
}
}
}

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

@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
}
public int NumCodes() => WebpConstants.NumLiteralCodes + WebpConstants.NumLengthCodes + ((this.PaletteCodeBits > 0) ? (1 << this.PaletteCodeBits) : 0);
public int NumCodes() => WebpConstants.NumLiteralCodes + WebpConstants.NumLengthCodes + (this.PaletteCodeBits > 0 ? 1 << this.PaletteCodeBits : 0);
/// <summary>
/// Estimate how many bits the combined entropy of literals and distance approximately maps to.
@ -234,7 +234,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
output.IsUsed[i] = this.IsUsed[i] | b.IsUsed[i];
}
output.TrivialSymbol = (this.TrivialSymbol == b.TrivialSymbol)
output.TrivialSymbol = this.TrivialSymbol == b.TrivialSymbol
? this.TrivialSymbol
: NonTrivialSym;
}

51
src/ImageSharp/Formats/WebP/Lossless/WebpLosslessDecoder.cs

@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
// 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);
bool colorCacheBitsIsValid = colorCacheBits >= 1 && colorCacheBits <= WebpConstants.MaxColorCacheBits + 1;
if (!colorCacheBitsIsValid)
{
WebpThrowHelper.ThrowImageFormatException("Invalid color cache bits found");
@ -426,7 +426,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int totalSize = 0;
bool isTrivialLiteral = true;
int maxBits = 0;
var codeLengths = new int[maxAlphabetSize];
int[] codeLengths = new int[maxAlphabetSize];
for (int j = 0; j < WebpConstants.HuffmanCodesPerMetaCode; j++)
{
int alphabetSize = WebpConstants.AlphabetSize[j];
@ -459,7 +459,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int k;
for (k = 1; k < alphabetSize; ++k)
{
var codeLengthK = codeLengths[k];
int codeLengthK = codeLengths[k];
if (codeLengthK > localMaxBits)
{
localMaxBits = codeLengthK;
@ -517,7 +517,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
uint firstSymbolLenCode = this.bitReader.ReadValue(1);
// The first code is either 1 bit or 8 bit code.
uint symbol = this.bitReader.ReadValue((firstSymbolLenCode == 0) ? 1 : 8);
uint symbol = this.bitReader.ReadValue(firstSymbolLenCode == 0 ? 1 : 8);
codeLengths[symbol] = 1;
// The second code (if present), is always 8 bit long.
@ -532,7 +532,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
// (ii) Normal Code Length Code:
// The code lengths of a Huffman code are read as follows: num_code_lengths specifies the number of code lengths;
// the rest of the code lengths (according to the order in kCodeLengthCodeOrder) are zeros.
var codeLengthCodeLengths = new int[NumCodeLengthCodes];
int[] codeLengthCodeLengths = new int[NumCodeLengthCodes];
uint numCodes = this.bitReader.ReadValue(4) + 4;
if (numCodes > NumCodeLengthCodes)
{
@ -644,9 +644,9 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
// The transform data contains color table size and the entries in the color table.
// 8 bit value for color table size.
uint numColors = this.bitReader.ReadValue(8) + 1;
int bits = (numColors > 16) ? 0
: (numColors > 4) ? 1
: (numColors > 2) ? 2
int bits = numColors > 16 ? 0
: numColors > 4 ? 1
: numColors > 2 ? 2
: 3;
transform.Bits = bits;
using (IMemoryOwner<uint> colorMap = this.DecodeImageStream(decoder, (int)numColors, 1, false))
@ -661,15 +661,15 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
case Vp8LTransformType.PredictorTransform:
case Vp8LTransformType.CrossColorTransform:
{
// The first 3 bits of prediction data define the block width and height in number of bits.
transform.Bits = (int)this.bitReader.ReadValue(3) + 2;
int blockWidth = LosslessUtils.SubSampleSize(transform.XSize, transform.Bits);
int blockHeight = LosslessUtils.SubSampleSize(transform.YSize, transform.Bits);
IMemoryOwner<uint> transformData = this.DecodeImageStream(decoder, blockWidth, blockHeight, false);
transform.Data = transformData;
break;
}
{
// The first 3 bits of prediction data define the block width and height in number of bits.
transform.Bits = (int)this.bitReader.ReadValue(3) + 2;
int blockWidth = LosslessUtils.SubSampleSize(transform.XSize, transform.Bits);
int blockHeight = LosslessUtils.SubSampleSize(transform.YSize, transform.Bits);
IMemoryOwner<uint> transformData = this.DecodeImageStream(decoder, blockWidth, blockHeight, false);
transform.Data = transformData;
break;
}
}
decoder.Transforms.Add(transform);
@ -732,7 +732,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int lastRow = height;
const int lenCodeLimit = WebpConstants.NumLiteralCodes + WebpConstants.NumLengthCodes;
int mask = hdr.HuffmanMask;
HTreeGroup[] htreeGroup = (pos < last) ? GetHTreeGroupForPos(hdr, col, row) : null;
HTreeGroup[] htreeGroup = pos < last ? GetHTreeGroupForPos(hdr, col, row) : null;
while (!this.bitReader.Eos && pos < last)
{
// Only update when changing tile.
@ -754,7 +754,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
col = 0;
++row;
if (row <= lastRow && (row % WebpConstants.NumArgbCacheRows == 0))
if (row <= lastRow && row % WebpConstants.NumArgbCacheRows == 0)
{
dec.ExtractPalettedAlphaRows(row);
}
@ -784,7 +784,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
col -= width;
++row;
if (row <= lastRow && (row % WebpConstants.NumArgbCacheRows == 0))
if (row <= lastRow && row % WebpConstants.NumArgbCacheRows == 0)
{
dec.ExtractPalettedAlphaRows(row);
}
@ -813,7 +813,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
decoder.Width = width;
decoder.Height = height;
decoder.Metadata.HuffmanXSize = LosslessUtils.SubSampleSize(width, numBits);
decoder.Metadata.HuffmanMask = (numBits == 0) ? ~0 : (1 << numBits) - 1;
decoder.Metadata.HuffmanMask = numBits == 0 ? ~0 : (1 << numBits) - 1;
}
private uint ReadPackedSymbols(HTreeGroup[] group, Span<uint> pixelData, int decodedPixels)
@ -879,11 +879,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
[MethodImpl(InliningOptions.ShortMethod)]
private int GetCopyLength(int lengthSymbol)
{
// Length and distance prefixes are encoded the same way.
return this.GetCopyDistance(lengthSymbol);
}
private int GetCopyLength(int lengthSymbol) =>
this.GetCopyDistance(lengthSymbol); // Length and distance prefixes are encoded the same way.
private int GetCopyDistance(int distanceSymbol)
{
@ -930,7 +927,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int dist = (yOffset * xSize) + xOffset;
// dist < 1 can happen if xSize is very small.
return (dist >= 1) ? dist : 1;
return dist >= 1 ? dist : 1;
}
/// <summary>

18
src/ImageSharp/Formats/WebP/Lossy/LossyUtils.cs

@ -506,7 +506,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
/// </summary>
public static void TransformWht(Span<short> input, Span<short> output)
{
var tmp = new int[16];
int[] tmp = new int[16];
for (int i = 0; i < 4; ++i)
{
int iPlus4 = 4 + i;
@ -732,7 +732,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
for (int k = 3; k > 0; --k)
{
offset += 4 * stride;
SimpleVFilter16(p, offset, stride, thresh);
SimpleVFilter16(p, offset, stride, thresh);
}
}
@ -833,7 +833,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
public static void Dst(Span<byte> dst, int x, int y, byte v) => dst[x + (y * WebpConstants.Bps)] = v;
[MethodImpl(InliningOptions.ShortMethod)]
public static byte Clip8B(int v) => (byte)((v & ~0xff) == 0 ? v : (v < 0) ? 0 : 255);
public static byte Clip8B(int v) => (byte)((v & ~0xff) == 0 ? v : v < 0 ? 0 : 255);
// Cost of coding one event with probability 'proba'.
public static int Vp8BitCost(int bit, byte proba) => bit == 0 ? WebpLookupTables.Vp8EntropyCost[proba] : WebpLookupTables.Vp8EntropyCost[255 - proba];
@ -882,7 +882,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int thresh2 = (2 * thresh) + 1;
while (size-- > 0)
{
if (NeedsFilter2(p, offset, hStride, thresh2, ithresh))
if (NeedsFilter2(p, offset, hStride, thresh2, ithresh))
{
if (Hev(p, offset, hStride, hevThresh))
{
@ -992,7 +992,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int p0 = p[offset - step];
int q0 = p[offset];
int q1 = p[offset + step];
return ((4 * WebpLookupTables.Abs0[p0 - q0]) + WebpLookupTables.Abs0[p1 - q1]) <= t;
return (4 * WebpLookupTables.Abs0[p0 - q0]) + WebpLookupTables.Abs0[p1 - q1] <= t;
}
private static bool NeedsFilter2(Span<byte> p, int offset, int step, int t, int it)
@ -1007,7 +1007,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int q1 = p[offset + step];
int q2 = p[offset + step2];
int q3 = p[offset + step3];
if (((4 * WebpLookupTables.Abs0[p0 - q0]) + WebpLookupTables.Abs0[p1 - q1]) > t)
if ((4 * WebpLookupTables.Abs0[p0 - q0]) + WebpLookupTables.Abs0[p1 - q1] > t)
{
return false;
}
@ -1024,7 +1024,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int p0 = p[offset - step];
int q0 = p[offset];
int q1 = p[offset + step];
return (WebpLookupTables.Abs0[p1 - p0] > thresh) || (WebpLookupTables.Abs0[q1 - q0] > thresh);
return WebpLookupTables.Abs0[p1 - p0] > thresh || WebpLookupTables.Abs0[q1 - q0] > thresh;
}
[MethodImpl(InliningOptions.ShortMethod)]
@ -1056,7 +1056,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
private static byte Clip8(int v)
{
int yuvMask = (256 << 6) - 1;
return (byte)(((v & ~yuvMask) == 0) ? (v >> 6) : (v < 0) ? 0 : 255);
return (byte)((v & ~yuvMask) == 0 ? v >> 6 : v < 0 ? 0 : 255);
}
[MethodImpl(InliningOptions.ShortMethod)]
@ -1081,6 +1081,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
}
[MethodImpl(InliningOptions.ShortMethod)]
private static int Clamp255(int x) => x < 0 ? 0 : (x > 255 ? 255 : x);
private static int Clamp255(int x) => x < 0 ? 0 : x > 255 ? 255 : x;
}
}

4
src/ImageSharp/Formats/WebP/Lossy/PassStats.cs

@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
this.Q = Numerics.Clamp(quality, qMin, qMax);
this.LastQ = this.Q;
this.Target = doSizeSearch ? targetSize
: (targetPsnr > 0.0f) ? targetPsnr
: targetPsnr > 0.0f ? targetPsnr
: 40.0f; // default, just in case
this.Value = 0.0f;
this.LastValue = 0.0f;
@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
float dq;
if (this.IsFirst)
{
dq = (this.Value > this.Target) ? -this.Dq : this.Dq;
dq = this.Value > this.Target ? -this.Dq : this.Dq;
this.IsFirst = false;
}
else if (this.Value != this.LastValue)

8
src/ImageSharp/Formats/WebP/Lossy/QuantEnc.cs

@ -350,7 +350,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
long bestScore = Vp8ModeScore.MaxCost;
int nz = 0;
int mode;
bool isI16 = tryBothModes || (it.CurrentMacroBlockInfo.MacroBlockType == Vp8MacroBlockType.I16X16);
bool isI16 = tryBothModes || it.CurrentMacroBlockInfo.MacroBlockType == Vp8MacroBlockType.I16X16;
Vp8SegmentInfo dqm = segmentInfos[it.CurrentMacroBlockInfo.Segment];
// Some empiric constants, of approximate order of magnitude.
@ -389,7 +389,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
// Avoid starting a checkerboard resonance from the border. See bug #432 of libwebp.
if (IsFlatSource16(src))
{
bestMode = (it.X == 0) ? 0 : 2;
bestMode = it.X == 0 ? 0 : 2;
tryBothModes = false; // Stick to i16.
}
}
@ -530,7 +530,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
}
}
return (last >= 0) ? 1 : 0;
return last >= 0 ? 1 : 0;
}
// Quantize as usual, but also compute and return the quantization error.
@ -615,7 +615,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
for (int i = 1; i < 16; ++i)
{
// omit DC, we're only interested in AC
score += (levels[i] != 0) ? 1 : 0;
score += levels[i] != 0 ? 1 : 0;
if (score > thresh)
{
return false;

8
src/ImageSharp/Formats/WebP/Lossy/Vp8Decoder.cs

@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int extraRows = WebpConstants.FilterExtraRows[(int)LoopFilter.Complex]; // assuming worst case: complex filter
int extraY = extraRows * this.CacheYStride;
int extraUv = (extraRows / 2) * this.CacheUvStride;
int extraUv = extraRows / 2 * this.CacheUvStride;
this.YuvBuffer = memoryAllocator.Allocate<byte>((WebpConstants.Bps * 17) + (WebpConstants.Bps * 9) + extraY);
this.CacheY = memoryAllocator.Allocate<byte>((16 * this.CacheYStride) + extraY);
int cacheUvSize = (16 * this.CacheUvStride) + extraUv;
@ -192,7 +192,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
/// <summary>
/// Gets the contextual macroblock info.
/// </summary>
public Vp8MacroBlock[] MacroBlockInfo { get; }
public Vp8MacroBlock[] MacroBlockInfo { get; }
/// <summary>
/// Gets or sets the loop filter used. The purpose of the loop filter is to eliminate (or at least reduce)
@ -284,7 +284,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
}
}
level = (level < 0) ? 0 : (level > 63) ? 63 : level;
level = level < 0 ? 0 : level > 63 ? 63 : level;
if (level > 0)
{
int iLevel = level;
@ -313,7 +313,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
info.InnerLevel = (byte)iLevel;
info.Limit = (byte)((2 * level) + iLevel);
info.HighEdgeVarianceThreshold = (byte)((level >= 40) ? 2 : (level >= 15) ? 1 : 0);
info.HighEdgeVarianceThreshold = (byte)(level >= 40 ? 2 : level >= 15 ? 1 : 0);
}
else
{

16
src/ImageSharp/Formats/WebP/Lossy/Vp8EncIterator.cs

@ -346,7 +346,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int q = quality;
int kThreshold = 8 + ((17 - 8) * q / 100);
int k;
var dc = new uint[16];
uint[] dc = new uint[16];
uint m;
uint m2;
for (k = 0; k < 16; k += 4)
@ -366,7 +366,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
}
else
{
var modes = new byte[16]; // DC4
byte[] modes = new byte[16]; // DC4
this.SetIntra4Mode(modes);
}
@ -418,7 +418,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
histos[curHisto] = new Vp8Histogram();
histos[curHisto].CollectHistogram(src, this.YuvP.AsSpan(Vp8Encoding.Vp8I4ModeOffsets[mode]), 0, 1);
var alpha = histos[curHisto].GetAlpha();
int alpha = histos[curHisto].GetAlpha();
if (alpha > bestModeAlpha)
{
bestModeAlpha = alpha;
@ -523,7 +523,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int ctx = this.TopNz[x] + this.LeftNz[y];
res.SetCoeffs(rd.YAcLevels.AsSpan((x + (y * 4)) * 16, 16));
r += res.GetResidualCost(ctx);
this.TopNz[x] = this.LeftNz[y] = (res.Last >= 0) ? 1 : 0;
this.TopNz[x] = this.LeftNz[y] = res.Last >= 0 ? 1 : 0;
}
}
@ -536,8 +536,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int predIdx = this.predIdx;
int x = this.I4 & 3;
int y = this.I4 >> 2;
int left = (x == 0) ? this.Preds[predIdx + (y * predsWidth) - 1] : modes[this.I4 - 1];
int top = (y == 0) ? this.Preds[predIdx - predsWidth + x] : modes[this.I4 - 4];
int left = x == 0 ? this.Preds[predIdx + (y * predsWidth) - 1] : modes[this.I4 - 1];
int top = y == 0 ? this.Preds[predIdx - predsWidth + x] : modes[this.I4 - 4];
return WebpLookupTables.Vp8FixedCostsI4[top, left];
}
@ -573,7 +573,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int ctx = this.TopNz[4 + ch + x] + this.LeftNz[4 + ch + y];
res.SetCoeffs(rd.UvLevels.AsSpan(((ch * 2) + x + (y * 2)) * 16, 16));
r += res.GetResidualCost(ctx);
this.TopNz[4 + ch + x] = this.LeftNz[4 + ch + y] = (res.Last >= 0) ? 1 : 0;
this.TopNz[4 + ch + x] = this.LeftNz[4 + ch + y] = res.Last >= 0 ? 1 : 0;
}
}
}
@ -910,7 +910,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
Span<byte> yLeft = this.YLeft.AsSpan();
Span<byte> uLeft = this.UvLeft.AsSpan(0, 16);
Span<byte> vLeft = this.UvLeft.AsSpan(16, 16);
byte val = (byte)((this.Y > 0) ? 129 : 127);
byte val = (byte)(this.Y > 0 ? 129 : 127);
yLeft[0] = val;
uLeft[0] = val;
vLeft[0] = val;

2
src/ImageSharp/Formats/WebP/Lossy/Vp8EncProba.cs

@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
{
Vp8ProbaArray p = this.Coeffs[ctype][band].Probabilities[ctx];
Vp8CostArray table = this.LevelCost[ctype][band].Costs[ctx];
int cost0 = (ctx > 0) ? LossyUtils.Vp8BitCost(1, p.Probabilities[0]) : 0;
int cost0 = ctx > 0 ? LossyUtils.Vp8BitCost(1, p.Probabilities[0]) : 0;
int costBase = LossyUtils.Vp8BitCost(1, p.Probabilities[1]) + cost0;
int v;
table.Costs[0] = (ushort)(LossyUtils.Vp8BitCost(0, p.Probabilities[1]) + cost0);

31
src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs

@ -99,6 +99,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
/// <param name="method">Quality/speed trade-off (0=fast, 6=slower-better).</param>
/// <param name="entropyPasses">Number of entropy-analysis passes (in [1..10]).</param>
/// <param name="filterStrength">The filter the strength of the deblocking filter, between 0 (no filtering) and 100 (maximum filtering).</param>
/// <param name="spatialNoiseShaping">The spatial noise shaping. 0=off, 100=maximum.</param>
public Vp8Encoder(MemoryAllocator memoryAllocator, Configuration configuration, int width, int height, int quality, int method, int entropyPasses, int filterStrength, int spatialNoiseShaping)
{
this.memoryAllocator = memoryAllocator;
@ -110,9 +111,9 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
this.entropyPasses = Numerics.Clamp(entropyPasses, 1, 10);
this.filterStrength = Numerics.Clamp(filterStrength, 0, 100);
this.spatialNoiseShaping = Numerics.Clamp(spatialNoiseShaping, 0, 100);
this.rdOptLevel = (method >= 6) ? Vp8RdLevel.RdOptTrellisAll
: (method >= 5) ? Vp8RdLevel.RdOptTrellis
: (method >= 3) ? Vp8RdLevel.RdOptBasic
this.rdOptLevel = method >= 6 ? Vp8RdLevel.RdOptTrellisAll
: method >= 5 ? Vp8RdLevel.RdOptTrellis
: method >= 3 ? Vp8RdLevel.RdOptBasic
: Vp8RdLevel.RdOptNone;
int pixelCount = width * height;
@ -362,7 +363,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
bool doSearch = targetSize > 0 || targetPsnr > 0;
bool fastProbe = (this.method == 0 || this.method == 3) && !doSearch;
int numPassLeft = this.entropyPasses;
Vp8RdLevel rdOpt = (this.method >= 3 || doSearch) ? Vp8RdLevel.RdOptBasic : Vp8RdLevel.RdOptNone;
Vp8RdLevel rdOpt = this.method >= 3 || doSearch ? Vp8RdLevel.RdOptBasic : Vp8RdLevel.RdOptNone;
int nbMbs = this.Mbw * this.Mbh;
var stats = new PassStats(targetSize, targetPsnr, QMin, QMax, this.quality);
@ -374,11 +375,11 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
if (this.method == 3)
{
// We need more stats for method 3 to be reliable.
nbMbs = (nbMbs > 200) ? nbMbs >> 1 : 100;
nbMbs = nbMbs > 200 ? nbMbs >> 1 : 100;
}
else
{
nbMbs = (nbMbs > 200) ? nbMbs >> 2 : 50;
nbMbs = nbMbs > 200 ? nbMbs >> 2 : 50;
}
}
@ -536,7 +537,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
// Simplified k-Means, to assign Nb segments based on alpha-histogram.
private void AssignSegments(int[] alphas)
{
int nb = (this.SegmentHeader.NumSegments < NumMbSegments) ? this.SegmentHeader.NumSegments : NumMbSegments;
int nb = this.SegmentHeader.NumSegments < NumMbSegments ? this.SegmentHeader.NumSegments : NumMbSegments;
int[] centers = new int[NumMbSegments];
int weightedAverage = 0;
int[] map = new int[WebpConstants.MaxAlpha + 1];
@ -727,7 +728,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
// Segments with lower complexity ('beta') will be less filtered.
int f = baseStrength * level0 / (256 + m.Beta);
m.FStrength = (f < WebpConstants.FilterStrengthCutoff) ? 0 : (f > 63) ? 63 : f;
m.FStrength = f < WebpConstants.FilterStrengthCutoff ? 0 : f > 63 ? 63 : f;
}
// We record the initial strength (mainly for the case of 1-segment only).
@ -754,7 +755,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
probas[1] = (byte)GetProba(p[0], p[1]);
probas[2] = (byte)GetProba(p[2], p[3]);
this.SegmentHeader.UpdateMap = (probas[0] != 255) || (probas[1] != 255) || (probas[2] != 255);
this.SegmentHeader.UpdateMap = probas[0] != 255 || probas[1] != 255 || probas[2] != 255;
if (!this.SegmentHeader.UpdateMap)
{
this.ResetSegments();
@ -969,7 +970,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
{
int ctx = it.TopNz[4 + ch + x] + it.LeftNz[4 + ch + y];
residual.SetCoeffs(rd.UvLevels.AsSpan(16 * ((ch * 2) + x + (y * 2)), 16));
var res = this.bitWriter.PutCoeffs(ctx, residual);
int res = this.bitWriter.PutCoeffs(ctx, residual);
it.TopNz[4 + ch + x] = it.LeftNz[4 + ch + y] = res;
}
}
@ -1018,7 +1019,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int ctx = it.TopNz[x] + it.LeftNz[y];
Span<short> coeffs = rd.YAcLevels.AsSpan(16 * (x + (y * 4)), 16);
residual.SetCoeffs(coeffs);
var res = residual.RecordCoeffs(ctx);
int res = residual.RecordCoeffs(ctx);
it.TopNz[x] = res;
it.LeftNz[y] = res;
}
@ -1059,7 +1060,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
[MethodImpl(InliningOptions.ShortMethod)]
private static double QualityToCompression(double c)
{
double linearC = (c < 0.75) ? c * (2.0d / 3.0d) : (2.0d * c) - 1.0d;
double linearC = c < 0.75 ? c * (2.0d / 3.0d) : (2.0d * c) - 1.0d;
// The file size roughly scales as pow(quantizer, 3.). Actually, the
// exponent is somewhere between 2.8 and 3.2, but we're mostly interested
@ -1075,18 +1076,18 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
[MethodImpl(InliningOptions.ShortMethod)]
private int FilterStrengthFromDelta(int sharpness, int delta)
{
int pos = (delta < WebpConstants.MaxDelzaSize) ? delta : WebpConstants.MaxDelzaSize - 1;
int pos = delta < WebpConstants.MaxDelzaSize ? delta : WebpConstants.MaxDelzaSize - 1;
return WebpLookupTables.LevelsFromDelta[sharpness, pos];
}
[MethodImpl(InliningOptions.ShortMethod)]
private static double GetPsnr(long mse, long size) => (mse > 0 && size > 0) ? 10.0f * Math.Log10(255.0f * 255.0f * size / mse) : 99;
private static double GetPsnr(long mse, long size) => mse > 0 && size > 0 ? 10.0f * Math.Log10(255.0f * 255.0f * size / mse) : 99;
[MethodImpl(InliningOptions.ShortMethod)]
private static int GetProba(int a, int b)
{
int total = a + b;
return (total == 0) ? 255 // that's the default probability.
return total == 0 ? 255 // that's the default probability.
: ((255 * a) + (total / 2)) / total; // rounded proba
}
}

89
src/ImageSharp/Formats/WebP/Lossy/Vp8Encoding.cs

@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
{
int i;
#pragma warning disable SA1312 // Variable names should begin with lower-case letter
var C = new int[4 * 4];
int[] C = new int[4 * 4];
#pragma warning restore SA1312 // Variable names should begin with lower-case letter
Span<int> tmp = C.AsSpan();
for (i = 0; i < 4; ++i)
@ -125,7 +125,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
public static void FTransform(Span<byte> src, Span<byte> reference, Span<short> output)
{
int i;
var tmp = new int[16];
int[] tmp = new int[16];
int srcIdx = 0;
int refIdx = 0;
for (i = 0; i < 4; ++i)
@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
public static void FTransformWht(Span<short> input, Span<short> output)
{
var tmp = new int[16];
int[] tmp = new int[16];
int i;
int inputIdx = 0;
for (i = 0; i < 4; ++i)
@ -299,7 +299,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
}
else
{
Vp8Encoding.HorizontalPred(dst, left, size);
HorizontalPred(dst, left, size);
}
}
else
@ -310,7 +310,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
// then 129, and not 127 as in the VerticalPred case.
if (top != null)
{
Vp8Encoding.VerticalPred(dst, top, size);
VerticalPred(dst, top, size);
}
else
{
@ -444,23 +444,23 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
byte d = top[topOffset + 3];
LossyUtils.Dst(dst, 0, 3, LossyUtils.Avg3(j, k, l));
var ijk = LossyUtils.Avg3(i, j, k);
byte ijk = LossyUtils.Avg3(i, j, k);
LossyUtils.Dst(dst, 0, 2, ijk);
LossyUtils.Dst(dst, 1, 3, ijk);
var xij = LossyUtils.Avg3(x, i, j);
byte xij = LossyUtils.Avg3(x, i, j);
LossyUtils.Dst(dst, 0, 1, xij);
LossyUtils.Dst(dst, 1, 2, xij);
LossyUtils.Dst(dst, 2, 3, xij);
var axi = LossyUtils.Avg3(a, x, i);
byte axi = LossyUtils.Avg3(a, x, i);
LossyUtils.Dst(dst, 0, 0, axi);
LossyUtils.Dst(dst, 1, 1, axi);
LossyUtils.Dst(dst, 2, 2, axi);
LossyUtils.Dst(dst, 3, 3, axi);
var bax = LossyUtils.Avg3(b, a, x);
byte bax = LossyUtils.Avg3(b, a, x);
LossyUtils.Dst(dst, 1, 0, bax);
LossyUtils.Dst(dst, 2, 1, bax);
LossyUtils.Dst(dst, 3, 2, bax);
var cba = LossyUtils.Avg3(c, b, a);
byte cba = LossyUtils.Avg3(c, b, a);
LossyUtils.Dst(dst, 2, 0, cba);
LossyUtils.Dst(dst, 3, 1, cba);
LossyUtils.Dst(dst, 3, 0, LossyUtils.Avg3(d, c, b));
@ -477,25 +477,25 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
byte c = top[topOffset + 2];
byte d = top[topOffset + 3];
var xa = LossyUtils.Avg2(x, a);
byte xa = LossyUtils.Avg2(x, a);
LossyUtils.Dst(dst, 0, 0, xa);
LossyUtils.Dst(dst, 1, 2, xa);
var ab = LossyUtils.Avg2(a, b);
byte ab = LossyUtils.Avg2(a, b);
LossyUtils.Dst(dst, 1, 0, ab);
LossyUtils.Dst(dst, 2, 2, ab);
var bc = LossyUtils.Avg2(b, c);
byte bc = LossyUtils.Avg2(b, c);
LossyUtils.Dst(dst, 2, 0, bc);
LossyUtils.Dst(dst, 3, 2, bc);
LossyUtils.Dst(dst, 3, 0, LossyUtils.Avg2(c, d));
LossyUtils.Dst(dst, 0, 3, LossyUtils.Avg3(k, j, i));
LossyUtils.Dst(dst, 0, 2, LossyUtils.Avg3(j, i, x));
var ixa = LossyUtils.Avg3(i, x, a);
byte ixa = LossyUtils.Avg3(i, x, a);
LossyUtils.Dst(dst, 0, 1, ixa);
LossyUtils.Dst(dst, 1, 3, ixa);
var xab = LossyUtils.Avg3(x, a, b);
byte xab = LossyUtils.Avg3(x, a, b);
LossyUtils.Dst(dst, 1, 1, xab);
LossyUtils.Dst(dst, 2, 3, xab);
var abc = LossyUtils.Avg3(a, b, c);
byte abc = LossyUtils.Avg3(a, b, c);
LossyUtils.Dst(dst, 2, 1, abc);
LossyUtils.Dst(dst, 3, 3, abc);
LossyUtils.Dst(dst, 3, 1, LossyUtils.Avg3(b, c, d));
@ -513,23 +513,23 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
byte h = top[topOffset + 7];
LossyUtils.Dst(dst, 0, 0, LossyUtils.Avg3(a, b, c));
var bcd = LossyUtils.Avg3(b, c, d);
byte bcd = LossyUtils.Avg3(b, c, d);
LossyUtils.Dst(dst, 1, 0, bcd);
LossyUtils.Dst(dst, 0, 1, bcd);
var cde = LossyUtils.Avg3(c, d, e);
byte cde = LossyUtils.Avg3(c, d, e);
LossyUtils.Dst(dst, 2, 0, cde);
LossyUtils.Dst(dst, 1, 1, cde);
LossyUtils.Dst(dst, 0, 2, cde);
var def = LossyUtils.Avg3(d, e, f);
byte def = LossyUtils.Avg3(d, e, f);
LossyUtils.Dst(dst, 3, 0, def);
LossyUtils.Dst(dst, 2, 1, def);
LossyUtils.Dst(dst, 1, 2, def);
LossyUtils.Dst(dst, 0, 3, def);
var efg = LossyUtils.Avg3(e, f, g);
byte efg = LossyUtils.Avg3(e, f, g);
LossyUtils.Dst(dst, 3, 1, efg);
LossyUtils.Dst(dst, 2, 2, efg);
LossyUtils.Dst(dst, 1, 3, efg);
var fgh = LossyUtils.Avg3(f, g, h);
byte fgh = LossyUtils.Avg3(f, g, h);
LossyUtils.Dst(dst, 3, 2, fgh);
LossyUtils.Dst(dst, 2, 3, fgh);
LossyUtils.Dst(dst, 3, 3, LossyUtils.Avg3(g, h, h));
@ -547,23 +547,23 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
byte h = top[topOffset + 7];
LossyUtils.Dst(dst, 0, 0, LossyUtils.Avg2(a, b));
var bc = LossyUtils.Avg2(b, c);
byte bc = LossyUtils.Avg2(b, c);
LossyUtils.Dst(dst, 1, 0, bc);
LossyUtils.Dst(dst, 0, 2, bc);
var cd = LossyUtils.Avg2(c, d);
byte cd = LossyUtils.Avg2(c, d);
LossyUtils.Dst(dst, 2, 0, cd);
LossyUtils.Dst(dst, 1, 2, cd);
var de = LossyUtils.Avg2(d, e);
byte de = LossyUtils.Avg2(d, e);
LossyUtils.Dst(dst, 3, 0, de);
LossyUtils.Dst(dst, 2, 2, de);
LossyUtils.Dst(dst, 0, 1, LossyUtils.Avg3(a, b, c));
var bcd = LossyUtils.Avg3(b, c, d);
byte bcd = LossyUtils.Avg3(b, c, d);
LossyUtils.Dst(dst, 1, 1, bcd);
LossyUtils.Dst(dst, 0, 3, bcd);
var cde = LossyUtils.Avg3(c, d, e);
byte cde = LossyUtils.Avg3(c, d, e);
LossyUtils.Dst(dst, 2, 1, cde);
LossyUtils.Dst(dst, 1, 3, cde);
var def = LossyUtils.Avg3(d, e, f);
byte def = LossyUtils.Avg3(d, e, f);
LossyUtils.Dst(dst, 3, 1, def);
LossyUtils.Dst(dst, 2, 3, def);
LossyUtils.Dst(dst, 3, 2, LossyUtils.Avg3(e, f, g));
@ -581,25 +581,25 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
byte b = top[topOffset + 1];
byte c = top[topOffset + 2];
var ix = LossyUtils.Avg2(i, x);
byte ix = LossyUtils.Avg2(i, x);
LossyUtils.Dst(dst, 0, 0, ix);
LossyUtils.Dst(dst, 2, 1, ix);
var ji = LossyUtils.Avg2(j, i);
byte ji = LossyUtils.Avg2(j, i);
LossyUtils.Dst(dst, 0, 1, ji);
LossyUtils.Dst(dst, 2, 2, ji);
var kj = LossyUtils.Avg2(k, j);
byte kj = LossyUtils.Avg2(k, j);
LossyUtils.Dst(dst, 0, 2, kj);
LossyUtils.Dst(dst, 2, 3, kj);
LossyUtils.Dst(dst, 0, 3, LossyUtils.Avg2(l, k));
LossyUtils.Dst(dst, 3, 0, LossyUtils.Avg3(a, b, c));
LossyUtils.Dst(dst, 2, 0, LossyUtils.Avg3(x, a, b));
var ixa = LossyUtils.Avg3(i, x, a);
byte ixa = LossyUtils.Avg3(i, x, a);
LossyUtils.Dst(dst, 1, 0, ixa);
LossyUtils.Dst(dst, 3, 1, ixa);
var jix = LossyUtils.Avg3(j, i, x);
byte jix = LossyUtils.Avg3(j, i, x);
LossyUtils.Dst(dst, 1, 1, jix);
LossyUtils.Dst(dst, 3, 2, jix);
var kji = LossyUtils.Avg3(k, j, i);
byte kji = LossyUtils.Avg3(k, j, i);
LossyUtils.Dst(dst, 1, 2, kji);
LossyUtils.Dst(dst, 3, 3, kji);
LossyUtils.Dst(dst, 1, 3, LossyUtils.Avg3(l, k, j));
@ -613,17 +613,17 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
byte l = top[topOffset - 5];
LossyUtils.Dst(dst, 0, 0, LossyUtils.Avg2(i, j));
var jk = LossyUtils.Avg2(j, k);
byte jk = LossyUtils.Avg2(j, k);
LossyUtils.Dst(dst, 2, 0, jk);
LossyUtils.Dst(dst, 0, 1, jk);
var kl = LossyUtils.Avg2(k, l);
byte kl = LossyUtils.Avg2(k, l);
LossyUtils.Dst(dst, 2, 1, kl);
LossyUtils.Dst(dst, 0, 2, kl);
LossyUtils.Dst(dst, 1, 0, LossyUtils.Avg3(i, j, k));
var jkl = LossyUtils.Avg3(j, k, l);
byte jkl = LossyUtils.Avg3(j, k, l);
LossyUtils.Dst(dst, 3, 0, jkl);
LossyUtils.Dst(dst, 1, 1, jkl);
var kll = LossyUtils.Avg3(k, l, l);
byte kll = LossyUtils.Avg3(k, l, l);
LossyUtils.Dst(dst, 3, 1, kll);
LossyUtils.Dst(dst, 1, 2, kll);
LossyUtils.Dst(dst, 3, 2, l);
@ -644,21 +644,12 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
}
[MethodImpl(InliningOptions.ShortMethod)]
private static byte Clip8b(int v)
{
return ((v & ~0xff) == 0) ? (byte)v : (v < 0) ? (byte)0 : (byte)255;
}
private static byte Clip8b(int v) => (v & ~0xff) == 0 ? (byte)v : v < 0 ? (byte)0 : (byte)255;
[MethodImpl(InliningOptions.ShortMethod)]
private static void Store(Span<byte> dst, Span<byte> reference, int x, int y, int v)
{
dst[x + (y * WebpConstants.Bps)] = LossyUtils.Clip8B(reference[x + (y * WebpConstants.Bps)] + (v >> 3));
}
private static void Store(Span<byte> dst, Span<byte> reference, int x, int y, int v) => dst[x + (y * WebpConstants.Bps)] = LossyUtils.Clip8B(reference[x + (y * WebpConstants.Bps)] + (v >> 3));
[MethodImpl(InliningOptions.ShortMethod)]
private static int Mul(int a, int b)
{
return (a * b) >> 16;
}
private static int Mul(int a, int b) => (a * b) >> 16;
}
}

6
src/ImageSharp/Formats/WebP/Lossy/Vp8Histogram.cs

@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
// for handling the useful small values which contribute most.
int maxValue = this.maxValue;
int lastNonZero = this.lastNonZero;
int alpha = (maxValue > 1) ? WebpConstants.AlphaScale * lastNonZero / maxValue : 0;
int alpha = maxValue > 1 ? WebpConstants.AlphaScale * lastNonZero / maxValue : 0;
return alpha;
}
@ -129,13 +129,13 @@ namespace SixLabors.ImageSharp.Formats.WebP.Lossy
int a2 = tmp[4 + i] - tmp[8 + i];
int a3 = tmp[0 + i] - tmp[12 + i];
output[0 + i] = (short)((a0 + a1 + 7) >> 4); // 12b
output[4 + i] = (short)((((a2 * 2217) + (a3 * 5352) + 12000) >> 16) + ((a3 != 0) ? 1 : 0));
output[4 + i] = (short)((((a2 * 2217) + (a3 * 5352) + 12000) >> 16) + (a3 != 0 ? 1 : 0));
output[8 + i] = (short)((a0 - a1 + 7) >> 4);
output[12 + i] = (short)(((a3 * 2217) - (a2 * 5352) + 51000) >> 16);
}
}
[MethodImpl(InliningOptions.ShortMethod)]
private static int ClipMax(int v, int max) => (v > max) ? max : v;
private static int ClipMax(int v, int max) => v > max ? max : v;
}
}

2
src/ImageSharp/Formats/WebP/Lossy/Vp8Matrix.cs

@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int i;
for (i = 0; i < 2; ++i)
{
int isAcCoeff = (i > 0) ? 1 : 0;
int isAcCoeff = i > 0 ? 1 : 0;
int bias = BiasMatrices[type][isAcCoeff];
this.IQ[i] = (ushort)((1 << WebpConstants.QFix) / this.Q[i]);
this.Bias[i] = (uint)this.BIAS(bias);

12
src/ImageSharp/Formats/WebP/Lossy/Vp8Residual.cs

@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
Vp8StatsArray s = this.Stats[n].Stats[ctx];
if (this.Last < 0)
{
this.RecordStats(0, s, 0);
this.RecordStats(0, s, 0);
return 0;
}
@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
}
this.RecordStats(1, s, 1);
var bit = (uint)(v + 1) > 2u;
bool bit = (uint)(v + 1) > 2u;
if (this.RecordStats(bit ? 1 : 0, s, 2) == 0)
{
// v = -1 or 1
@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
// bitCost(1, p0) is already incorporated in t[] tables, but only if ctx != 0
// (as required by the syntax). For ctx0 == 0, we need to add it here or it'll
// be missing during the loop.
int cost = (ctx0 == 0) ? LossyUtils.Vp8BitCost(1, (byte)p0) : 0;
int cost = ctx0 == 0 ? LossyUtils.Vp8BitCost(1, (byte)p0) : 0;
if (this.Last < 0)
{
@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
for (; n < this.Last; ++n)
{
v = Math.Abs(this.Coeffs[n]);
int ctx = (v >= 2) ? 2 : v;
int ctx = v >= 2 ? 2 : v;
cost += LevelCost(t.Costs, v);
t = costs[n + 1].Costs[ctx];
}
@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
if (n < 15)
{
int b = WebpConstants.Vp8EncBands[n + 1];
int ctx = (v == 1) ? 1 : 2;
int ctx = v == 1 ? 1 : 2;
int lastP0 = this.Prob[b].Probabilities[ctx].Probabilities[0];
cost += LossyUtils.Vp8BitCost(0, (byte)lastP0);
}
@ -152,7 +152,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
}
private static int LevelCost(Span<ushort> table, int level)
=> WebpLookupTables.Vp8LevelFixedCosts[level] + table[(level > WebpConstants.MaxVariableLevel) ? WebpConstants.MaxVariableLevel : level];
=> WebpLookupTables.Vp8LevelFixedCosts[level] + table[level > WebpConstants.MaxVariableLevel ? WebpConstants.MaxVariableLevel : level];
private int RecordStats(int bit, Vp8StatsArray statsArr, int idx)
{

4
src/ImageSharp/Formats/WebP/Lossy/Vp8SegmentInfo.cs

@ -74,8 +74,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int v0 = Math.Abs(dcs[1]);
int v1 = Math.Abs(dcs[2]);
int v2 = Math.Abs(dcs[4]);
int maxV = (v1 > v0) ? v1 : v0;
maxV = (v2 > maxV) ? v2 : maxV;
int maxV = v1 > v0 ? v1 : v0;
maxV = v2 > maxV ? v2 : maxV;
if (maxV > this.MaxEdge)
{
this.MaxEdge = maxV;

5
src/ImageSharp/Formats/WebP/Lossy/Vp8StatsArray.cs

@ -8,10 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
/// <summary>
/// Initializes a new instance of the <see cref="Vp8StatsArray"/> class.
/// </summary>
public Vp8StatsArray()
{
this.Stats = new uint[WebpConstants.NumProbas];
}
public Vp8StatsArray() => this.Stats = new uint[WebpConstants.NumProbas];
public uint[] Stats { get; }
}

42
src/ImageSharp/Formats/WebP/Lossy/WebpLossyDecoder.cs

@ -277,7 +277,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
Span<byte> vDst = yuv.Slice(vOff);
// Initialize left-most block.
var end = 16 * WebpConstants.Bps;
int end = 16 * WebpConstants.Bps;
for (int i = 0; i < end; i += WebpConstants.Bps)
{
yuv[i - 1 + yOff] = 129;
@ -365,7 +365,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
if (mbx >= dec.MbWidth - 1)
{
// On rightmost border.
var topYuv15 = topYuv.Y[15];
byte topYuv15 = topYuv.Y[15];
topRight[0] = topYuv15;
topRight[1] = topYuv15;
topRight[2] = topYuv15;
@ -421,7 +421,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
break;
}
this.DoTransform(bits, coeffs.AsSpan(n * 16), dst);
this.DoTransform(bits, coeffs.AsSpan(n * 16), dst);
}
}
else
@ -606,15 +606,14 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
{
int extraYRows = WebpConstants.FilterExtraRows[(int)dec.Filter];
int ySize = extraYRows * dec.CacheYStride;
int uvSize = (extraYRows / 2) * dec.CacheUvStride;
int uvSize = extraYRows / 2 * dec.CacheUvStride;
Span<byte> yDst = dec.CacheY.Memory.Span;
Span<byte> uDst = dec.CacheU.Memory.Span;
Span<byte> vDst = dec.CacheV.Memory.Span;
int mby = dec.MbY;
bool isFirstRow = mby == 0;
bool isLastRow = mby >= dec.BottomRightMbY - 1;
bool filterRow = (dec.Filter != LoopFilter.None) &&
(dec.MbY >= dec.TopLeftMbY) && (dec.MbY <= dec.BottomRightMbY);
bool filterRow = dec.Filter != LoopFilter.None && dec.MbY >= dec.TopLeftMbY && dec.MbY <= dec.BottomRightMbY;
if (filterRow)
{
@ -698,8 +697,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
}
// Loop over each output pairs of row.
var bufferStride2 = 2 * bufferStride;
var ioStride2 = 2 * io.YStride;
int bufferStride2 = 2 * bufferStride;
int ioStride2 = 2 * io.YStride;
for (; y + 2 < yEnd; y += 2)
{
topU = curU;
@ -879,7 +878,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
else
{
// Parse DC
var dc = new short[16];
short[] dc = new short[16];
int ctx = (int)(mb.NoneZeroDcCoeffs + leftMb.NoneZeroDcCoeffs);
int nz = this.GetCoeffs(br, bands[1], ctx, q.Y2Mat, 0, dc);
mb.NoneZeroDcCoeffs = leftMb.NoneZeroDcCoeffs = (uint)(nz > 0 ? 1 : 0);
@ -913,7 +912,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
{
int ctx = l + (tnz & 1);
int nz = this.GetCoeffs(br, acProba, ctx, q.Y1Mat, first, dst.AsSpan(dstOffset));
l = (nz > first) ? 1 : 0;
l = nz > first ? 1 : 0;
tnz = (byte)((tnz >> 1) | (l << 7));
nzCoeffs = NzCodeBits(nzCoeffs, nz, dst[dstOffset] != 0 ? 1 : 0);
dstOffset += 16;
@ -930,7 +929,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
for (int ch = 0; ch < 4; ch += 2)
{
uint nzCoeffs = 0;
var chPlus4 = 4 + ch;
int chPlus4 = 4 + ch;
tnz = (byte)(mb.NoneZeroAcDcCoeffs >> chPlus4);
lnz = (byte)(leftMb.NoneZeroAcDcCoeffs >> chPlus4);
for (int y = 0; y < 2; ++y)
@ -940,7 +939,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
{
int ctx = l + (tnz & 1);
int nz = this.GetCoeffs(br, bands[2], ctx, q.UvMat, 0, dst.AsSpan(dstOffset));
l = (nz > 0) ? 1 : 0;
l = nz > 0 ? 1 : 0;
tnz = (byte)((tnz >> 1) | (l << 3));
nzCoeffs = NzCodeBits(nzCoeffs, nz, dst[dstOffset] != 0 ? 1 : 0);
dstOffset += 16;
@ -952,7 +951,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
// Note: we don't really need the per-4x4 details for U/V blocks.
nonZeroUv |= nzCoeffs << (4 * ch);
outTnz |= (uint)((tnz << 4) << ch);
outTnz |= (uint)(tnz << 4 << ch);
outLnz |= (uint)((lnz & 0xf0) << ch);
}
@ -1128,7 +1127,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
vp8FilterHeader.Sharpness = (int)this.bitReader.ReadValue(3);
vp8FilterHeader.UseLfDelta = this.bitReader.ReadBool();
dec.Filter = (vp8FilterHeader.FilterLevel == 0) ? LoopFilter.None : vp8FilterHeader.LoopFilter;
dec.Filter = vp8FilterHeader.FilterLevel == 0 ? LoopFilter.None : vp8FilterHeader.LoopFilter;
if (vp8FilterHeader.UseLfDelta)
{
// Update lf-delta?
@ -1157,7 +1156,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int extraRows = WebpConstants.FilterExtraRows[(int)dec.Filter];
int extraY = extraRows * dec.CacheYStride;
int extraUv = (extraRows / 2) * dec.CacheUvStride;
int extraUv = extraRows / 2 * dec.CacheUvStride;
dec.CacheYOffset = extraY;
dec.CacheUvOffset = extraUv;
}
@ -1313,7 +1312,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
{
// For simple filter, we include 'extraPixels' on the other side of the boundary,
// since vertical or horizontal filtering of the previous macroblock can modify some abutting pixels.
var extraShift4 = (-extraPixels) >> 4;
int extraShift4 = -extraPixels >> 4;
dec.TopLeftMbX = extraShift4;
dec.TopLeftMbY = extraShift4;
if (dec.TopLeftMbX < 0)
@ -1347,7 +1346,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
private static uint NzCodeBits(uint nzCoeffs, int nz, int dcNz)
{
nzCoeffs <<= 2;
nzCoeffs |= (uint)((nz > 3) ? 3 : (nz > 1) ? 2 : dcNz);
nzCoeffs |= (uint)(nz > 3 ? 3 : nz > 1 ? 2 : dcNz);
return nzCoeffs;
}
@ -1359,12 +1358,12 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
{
if (mbx == 0)
{
return (mby == 0)
return mby == 0
? 6 // B_DC_PRED_NOTOPLEFT
: 5; // B_DC_PRED_NOLEFT
}
return (mby == 0)
return mby == 0
? 4 // B_DC_PRED_NOTOP
: 0; // B_DC_PRED
}
@ -1373,9 +1372,6 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
}
[MethodImpl(InliningOptions.ShortMethod)]
private static int Clip(int value, int max)
{
return value < 0 ? 0 : value > max ? max : value;
}
private static int Clip(int value, int max) => value < 0 ? 0 : value > max ? max : value;
}
}

4
src/ImageSharp/Formats/WebP/Lossy/YuvConversion.cs

@ -170,7 +170,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
Bgra32 bgra1;
int i, j;
int dstIdx = 0;
for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2, dstIdx += 4)
for (i = 0, j = 0; i < width >> 1; i += 1, j += 2, dstIdx += 4)
{
bgra0 = rowSpan[j];
bgra1 = rowSpan[j + 1];
@ -291,7 +291,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
private static int ClipUv(int uv, int rounding)
{
uv = (uv + rounding + (128 << (YuvFix + 2))) >> (YuvFix + 2);
return ((uv & ~0xff) == 0) ? uv : (uv < 0) ? 0 : 255;
return (uv & ~0xff) == 0 ? uv : uv < 0 ? 0 : 255;
}
}
}

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

@ -340,7 +340,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
public static readonly byte[] Cat4 = { 176, 155, 140, 135 };
public static readonly byte[] Cat5 = { 180, 157, 141, 134, 130 };
public static readonly byte[] Cat6 = { 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129 };
public static readonly byte[] Zigzag = { 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 };
public static readonly byte[] Zigzag = { 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 };
public static readonly sbyte[] YModesIntra4 =
{

8
src/ImageSharp/Formats/WebP/WebpDecoderCore.cs

@ -429,7 +429,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
}
else
{
var iccpData = new byte[iccpChunkSize];
byte[] iccpData = new byte[iccpChunkSize];
this.currentStream.Read(iccpData, 0, (int)iccpChunkSize);
var profile = new IccProfile(iccpData);
if (profile.CheckIsValid())
@ -447,7 +447,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
case WebpChunkType.Alpha:
uint alphaChunkSize = this.ReadChunkSize();
features.AlphaChunkHeader = (byte)this.currentStream.ReadByte();
var alphaDataSize = (int)(alphaChunkSize - 1);
int alphaDataSize = (int)(alphaChunkSize - 1);
features.AlphaData = this.memoryAllocator.Allocate<byte>(alphaDataSize);
this.currentStream.Read(features.AlphaData.Memory.Span, 0, alphaDataSize);
break;
@ -467,7 +467,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
return;
}
var streamLength = this.currentStream.Length;
long streamLength = this.currentStream.Length;
while (this.currentStream.Position < streamLength)
{
// Read chunk header.
@ -476,7 +476,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
if (chunkType == WebpChunkType.Exif && this.Metadata.ExifProfile == null)
{
var exifData = new byte[chunkLength];
byte[] exifData = new byte[chunkLength];
this.currentStream.Read(exifData, 0, (int)chunkLength);
this.Metadata.ExifProfile = new ExifProfile(exifData);
}

5
src/ImageSharp/Formats/WebP/WebpFeatures.cs

@ -47,9 +47,6 @@ namespace SixLabors.ImageSharp.Formats.Webp
public bool Animation { get; set; }
/// <inheritdoc/>
public void Dispose()
{
this.AlphaData?.Dispose();
}
public void Dispose() => this.AlphaData?.Dispose();
}
}

22
src/ImageSharp/Formats/WebP/WebpImageFormatDetector.cs

@ -14,36 +14,22 @@ namespace SixLabors.ImageSharp.Formats.Webp
public int HeaderSize => 12;
/// <inheritdoc />
public IImageFormat DetectFormat(ReadOnlySpan<byte> header)
{
return this.IsSupportedFileFormat(header) ? WebpFormat.Instance : null;
}
public IImageFormat DetectFormat(ReadOnlySpan<byte> header) => this.IsSupportedFileFormat(header) ? WebpFormat.Instance : null;
private bool IsSupportedFileFormat(ReadOnlySpan<byte> header)
{
return header.Length >= this.HeaderSize &&
this.IsRiffContainer(header) &&
this.IsWebPFile(header);
}
private bool IsSupportedFileFormat(ReadOnlySpan<byte> header) => header.Length >= this.HeaderSize && this.IsRiffContainer(header) && this.IsWebPFile(header);
/// <summary>
/// Checks, if the header starts with a valid RIFF FourCC.
/// </summary>
/// <param name="header">The header bytes.</param>
/// <returns>True, if its a valid RIFF FourCC.</returns>
private bool IsRiffContainer(ReadOnlySpan<byte> header)
{
return header.Slice(0, 4).SequenceEqual(WebpConstants.RiffFourCc);
}
private bool IsRiffContainer(ReadOnlySpan<byte> header) => header.Slice(0, 4).SequenceEqual(WebpConstants.RiffFourCc);
/// <summary>
/// Checks if 'WEBP' is present in the header.
/// </summary>
/// <param name="header">The header bytes.</param>
/// <returns>True, if its a webp file.</returns>
private bool IsWebPFile(ReadOnlySpan<byte> header)
{
return header.Slice(8, 4).SequenceEqual(WebpConstants.WebPHeader);
}
private bool IsWebPFile(ReadOnlySpan<byte> header) => header.Slice(8, 4).SequenceEqual(WebpConstants.WebPHeader);
}
}

6
src/ImageSharp/Formats/WebP/WebpLookupTables.cs

@ -1242,19 +1242,19 @@ namespace SixLabors.ImageSharp.Formats.Webp
Clip1 = new Dictionary<int, byte>();
for (int i = -255; i <= 255 + 255; ++i)
{
Clip1[i] = (byte)((i < 0) ? 0 : (i > 255) ? 255 : i);
Clip1[i] = (byte)(i < 0 ? 0 : i > 255 ? 255 : i);
}
Sclip1 = new Dictionary<int, sbyte>();
for (int i = -1020; i <= 1020; ++i)
{
Sclip1[i] = (sbyte)((i < -128) ? -128 : (i > 127) ? 127 : i);
Sclip1[i] = (sbyte)(i < -128 ? -128 : i > 127 ? 127 : i);
}
Sclip2 = new Dictionary<int, sbyte>();
for (int i = -112; i <= 112; ++i)
{
Sclip2[i] = (sbyte)((i < -16) ? -16 : (i > 15) ? 15 : i);
Sclip2[i] = (sbyte)(i < -16 ? -16 : i > 15 ? 15 : i);
}
InitializeModesProbabilities();

Loading…
Cancel
Save