Browse Source

Fix some issues in Vp8BitReader

pull/1552/head
Brian Popow 6 years ago
parent
commit
2acb3df0ea
  1. 2
      src/ImageSharp/Formats/WebP/LoopFilter.cs
  2. 38
      src/ImageSharp/Formats/WebP/Vp8BitReader.cs
  3. 27
      src/ImageSharp/Formats/WebP/WebPDecoderCore.cs
  4. 2
      src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs

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

@ -5,7 +5,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
internal enum LoopFilter
{
Normal,
Complex,
Simple,
None
}

38
src/ImageSharp/Formats/WebP/Vp8BitReader.cs

@ -36,16 +36,6 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
private byte buf;
/// <summary>
/// End of read buffer.
/// </summary>
// private byte bufEnd;
/// <summary>
/// Max packed-read position on buffer.
/// </summary>
// private byte bufMax;
/// <summary>
/// True if input is exhausted.
/// </summary>
@ -68,7 +58,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
this.range = 255 - 1;
this.value = 0;
this.bits = -8; // to load the very first 8bits;
this.bits = -8; // to load the very first 8bits.
this.eof = false;
this.pos = 0;
@ -87,7 +77,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
int pos = this.bits;
uint split = (uint)((range * prob) >> 8);
bool bit = this.value > split;
ulong value = this.value >> pos;
bool bit = value > split;
if (bit)
{
range -= split;
@ -117,9 +108,9 @@ namespace SixLabors.ImageSharp.Formats.WebP
Guard.MustBeGreaterThan(nBits, 0, nameof(nBits));
uint v = 0;
while (this.bits-- > 0)
while (nBits-- > 0)
{
v |= (uint)this.GetBit(0x80) << this.bits;
v |= (uint)this.GetBit(0x80) << nBits;
}
return v;
@ -140,7 +131,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
ulong bits;
ulong inBits = BinaryPrimitives.ReadUInt64LittleEndian(this.Data.AsSpan().Slice((int)this.pos, 8));
this.pos += BitsCount >> 3;
this.buf = this.Data[BitsCount >> 3];
this.buf = this.Data[this.pos];
bits = this.ByteSwap64(inBits);
bits >>= 64 - BitsCount;
this.value = bits | (this.value << BitsCount);
@ -182,9 +173,20 @@ namespace SixLabors.ImageSharp.Formats.WebP
private int BitsLog2Floor(uint n)
{
long firstSetBit;
throw new NotImplementedException();
// BitScanReverse(firstSetBit, n);
// Search the mask data from most significant bit (MSB) to least significant bit (LSB) for a set bit (1).
// https://docs.microsoft.com/en-us/cpp/intrinsics/bitscanreverse-bitscanreverse64?view=vs-2019
uint mask = 1;
for (int y = 0; y < 32; y++)
{
if ((mask & n) == mask)
{
return y;
}
mask <<= 1;
}
return 0;
}
}
}

27
src/ImageSharp/Formats/WebP/WebPDecoderCore.cs

@ -284,7 +284,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
{
this.webpMetadata.Format = WebPFormatType.Lossy;
// VP8 data size.
// VP8 data size (not including this 4 bytes).
this.currentStream.Read(this.buffer, 0, 4);
uint dataSize = BinaryPrimitives.ReadUInt32LittleEndian(this.buffer);
@ -339,6 +339,13 @@ namespace SixLabors.ImageSharp.Formats.WebP
WebPThrowHelper.ThrowImageFormatException("width or height can not be zero");
}
// The size of the encoded image data payload.
uint imageDataSize = dataSize - 10; // we have read 10 bytes already.
if (partitionLength > imageDataSize)
{
WebPThrowHelper.ThrowImageFormatException("bad partition length");
}
var vp8FrameHeader = new Vp8FrameHeader()
{
KeyFrame = true,
@ -346,7 +353,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
PartitionLength = partitionLength
};
var bitReader = new Vp8BitReader(this.currentStream, dataSize - 10, this.memoryAllocator);
var bitReader = new Vp8BitReader(
this.currentStream,
imageDataSize,
this.memoryAllocator);
// Paragraph 9.2: color space and clamp type follow
sbyte colorSpace = (sbyte)bitReader.ReadValue(1);
@ -394,10 +404,14 @@ namespace SixLabors.ImageSharp.Formats.WebP
// Paragraph 9.4: Parse the filter specs.
var vp8FilterHeader = new Vp8FilterHeader();
vp8FilterHeader.LoopFilter = bitReader.ReadBool() ? LoopFilter.Simple : LoopFilter.Normal;
vp8FilterHeader.LoopFilter = bitReader.ReadBool() ? LoopFilter.Simple : LoopFilter.Complex;
vp8FilterHeader.Level = (int)bitReader.ReadValue(6);
vp8FilterHeader.Sharpness = (int)bitReader.ReadValue(3);
vp8FilterHeader.UseLfDelta = bitReader.ReadBool();
// TODO: use enum here?
// 0 = 0ff, 1 = simple, 2 = complex
int filterType = (vp8FilterHeader.Level is 0) ? 0 : vp8FilterHeader.LoopFilter is LoopFilter.Simple ? 1 : 2;
if (vp8FilterHeader.UseLfDelta)
{
// Update lf-delta?
@ -423,7 +437,12 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
}
// TODO: ParsePartitions
// Paragraph 9.5: ParsePartitions.
int numPartsMinusOne = (1 << (int)bitReader.ReadValue(2)) - 1;
int lastPart = numPartsMinusOne;
// TODO: check if we have enough data available here, throw exception if not
return new WebPImageInfo()
{

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

@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
switch (version)
{
case 0:
return new Vp8Profile { ReconstructionFilter = ReconstructionFilter.Bicubic, LoopFilter = LoopFilter.Normal };
return new Vp8Profile { ReconstructionFilter = ReconstructionFilter.Bicubic, LoopFilter = LoopFilter.Complex };
case 1:
return new Vp8Profile { ReconstructionFilter = ReconstructionFilter.Bilinear, LoopFilter = LoopFilter.Simple };
case 2:

Loading…
Cancel
Save