diff --git a/src/ImageSharp/Formats/WebP/WebPDecoderBase.cs b/src/ImageSharp/Formats/WebP/WebPDecoderBase.cs
index 9779b2dfe8..b9c82c7ecb 100644
--- a/src/ImageSharp/Formats/WebP/WebPDecoderBase.cs
+++ b/src/ImageSharp/Formats/WebP/WebPDecoderBase.cs
@@ -27,6 +27,30 @@ namespace SixLabors.ImageSharp.Formats.WebP
return huffmanImageSpan[(xSize * (y >> bits)) + (x >> bits)];
}
+ ///
+ /// Decodes the next Huffman code from bit-stream.
+ /// FillBitWindow(br) needs to be called at minimum every second call
+ /// to ReadSymbol, in order to pre-fetch enough bits.
+ ///
+ protected uint ReadSymbol(Span table, Vp8LBitReader bitReader)
+ {
+ // TODO: if the bitReader field is moved to this base class we could omit the parameter.
+ uint val = (uint)bitReader.PrefetchBits();
+ Span tableSpan = table.Slice((int)(val & HuffmanUtils.HuffmanTableMask));
+ int nBits = tableSpan[0].BitsUsed - HuffmanUtils.HuffmanTableBits;
+ if (nBits > 0)
+ {
+ bitReader.AdvanceBitPosition(HuffmanUtils.HuffmanTableBits);
+ val = (uint)bitReader.PrefetchBits();
+ tableSpan = tableSpan.Slice((int)tableSpan[0].Value);
+ tableSpan = tableSpan.Slice((int)val & ((1 << nBits) - 1));
+ }
+
+ bitReader.AdvanceBitPosition(tableSpan[0].BitsUsed);
+
+ return tableSpan[0].Value;
+ }
+
protected int GetCopyDistance(int distanceSymbol, Vp8LBitReader bitReader)
{
if (distanceSymbol < 4)
diff --git a/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs b/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs
index 40f13aaea3..ab4dd63069 100644
--- a/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs
+++ b/src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs
@@ -235,7 +235,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
else
{
- code = (int)this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Green]);
+ code = (int)this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Green], this.bitReader);
}
if (this.bitReader.IsEndOfStream())
@@ -252,10 +252,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
else
{
- uint red = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Red]);
+ uint red = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Red], this.bitReader);
this.bitReader.FillBitWindow();
- uint blue = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Blue]);
- uint alpha = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Alpha]);
+ uint blue = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Blue], this.bitReader);
+ uint alpha = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Alpha], this.bitReader);
if (this.bitReader.IsEndOfStream())
{
break;
@@ -272,7 +272,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
// Backward reference is used.
int lengthSym = code - WebPConstants.NumLiteralCodes;
int length = this.GetCopyLength(lengthSym, this.bitReader);
- uint distSymbol = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Dist]);
+ uint distSymbol = this.ReadSymbol(hTreeGroup[0].HTrees[HuffIndex.Dist], this.bitReader);
this.bitReader.FillBitWindow();
int distCode = this.GetCopyDistance((int)distSymbol, this.bitReader);
int dist = this.PlaneCodeToDistance(width, distCode);
@@ -691,29 +691,6 @@ namespace SixLabors.ImageSharp.Formats.WebP
decoder.Metadata.HuffmanMask = (numBits is 0) ? ~0 : (1 << numBits) - 1;
}
- ///
- /// Decodes the next Huffman code from bit-stream.
- /// FillBitWindow(br) needs to be called at minimum every second call
- /// to ReadSymbol, in order to pre-fetch enough bits.
- ///
- private uint ReadSymbol(Span table)
- {
- uint val = (uint)this.bitReader.PrefetchBits();
- Span tableSpan = table.Slice((int)(val & HuffmanUtils.HuffmanTableMask));
- int nBits = tableSpan[0].BitsUsed - HuffmanUtils.HuffmanTableBits;
- if (nBits > 0)
- {
- this.bitReader.AdvanceBitPosition(HuffmanUtils.HuffmanTableBits);
- val = (uint)this.bitReader.PrefetchBits();
- tableSpan = tableSpan.Slice((int)tableSpan[0].Value);
- tableSpan = tableSpan.Slice((int)val & ((1 << nBits) - 1));
- }
-
- this.bitReader.AdvanceBitPosition(tableSpan[0].BitsUsed);
-
- return tableSpan[0].Value;
- }
-
private uint ReadPackedSymbols(HTreeGroup[] group, Span pixelData, int decodedPixels)
{
uint val = (uint)(this.bitReader.PrefetchBits() & (HuffmanUtils.HuffmanPackedTableSize - 1));