Browse Source

Fix decoding very small lossy webp images

pull/1552/head
Brian Popow 6 years ago
parent
commit
0af68d8a6b
  1. 21
      src/ImageSharp/Formats/WebP/Vp8Decoder.cs
  2. 20
      src/ImageSharp/Formats/WebP/WebPLossyDecoder.cs

21
src/ImageSharp/Formats/WebP/Vp8Decoder.cs

@ -50,12 +50,15 @@ namespace SixLabors.ImageSharp.Formats.WebP
uint height = pictureHeader.Height; uint height = pictureHeader.Height;
// TODO: use memory allocator // TODO: use memory allocator
this.CacheY = new byte[width * height]; // TODO: this is way too much mem, figure out what the min req is. int extraRows = WebPConstants.FilterExtraRows[2]; // TODO: assuming worst case: complex filter
this.CacheU = new byte[width * height]; int extraY = extraRows * this.CacheYStride;
this.CacheV = new byte[width * height]; int extraUv = (extraRows / 2) * this.CacheUvStride;
this.TmpYBuffer = new byte[width * height]; // TODO: figure out min buffer length this.CacheY = new byte[width * height + extraY + 256]; // TODO: this is way too much mem, figure out what the min req is.
this.TmpUBuffer = new byte[width * height]; // TODO: figure out min buffer length this.CacheU = new byte[width * height + extraUv + 256];
this.TmpVBuffer = new byte[width * height]; // TODO: figure out min buffer length this.CacheV = new byte[width * height + extraUv + 256];
this.TmpYBuffer = new byte[width * height + extraY]; // TODO: figure out min buffer length
this.TmpUBuffer = new byte[width * height + extraUv]; // TODO: figure out min buffer length
this.TmpVBuffer = new byte[width * height + extraUv]; // TODO: figure out min buffer length
this.Bgr = new byte[width * height * 4]; this.Bgr = new byte[width * height * 4];
for (int i = 0; i < this.YuvBuffer.Length; i++) for (int i = 0; i < this.YuvBuffer.Length; i++)
@ -66,6 +69,10 @@ namespace SixLabors.ImageSharp.Formats.WebP
for (int i = 0; i < this.CacheY.Length; i++) for (int i = 0; i < this.CacheY.Length; i++)
{ {
this.CacheY[i] = 205; this.CacheY[i] = 205;
}
for (int i = 0; i < this.CacheU.Length; i++)
{
this.CacheU[i] = 205; this.CacheU[i] = 205;
this.CacheV[i] = 205; this.CacheV[i] = 205;
} }
@ -82,7 +89,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
public Vp8SegmentHeader SegmentHeader { get; } public Vp8SegmentHeader SegmentHeader { get; }
// number of partitions minus one. // number of partitions minus one.
public uint NumPartsMinusOne { get; } public int NumPartsMinusOne { get; set; }
// per-partition boolean decoders. // per-partition boolean decoders.
public Vp8BitReader[] Vp8BitReaders { get; } public Vp8BitReader[] Vp8BitReaders { get; }

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

@ -452,13 +452,13 @@ namespace SixLabors.ImageSharp.Formats.WebP
Span<byte> vOut = dec.CacheV.AsSpan(dec.CacheUvOffset + (mbx * 8)); Span<byte> vOut = dec.CacheV.AsSpan(dec.CacheUvOffset + (mbx * 8));
for (int j = 0; j < 16; ++j) for (int j = 0; j < 16; ++j)
{ {
yDst.Slice(j * WebPConstants.Bps, 16).CopyTo(yOut.Slice(j * dec.CacheYStride)); yDst.Slice(j * WebPConstants.Bps, Math.Min(16, yOut.Length)).CopyTo(yOut.Slice(j * dec.CacheYStride));
} }
for (int j = 0; j < 8; ++j) for (int j = 0; j < 8; ++j)
{ {
uDst.Slice(j * WebPConstants.Bps, 8).CopyTo(uOut.Slice(j * dec.CacheUvStride)); uDst.Slice(j * WebPConstants.Bps, Math.Min(8, uOut.Length)).CopyTo(uOut.Slice(j * dec.CacheUvStride));
vDst.Slice(j * WebPConstants.Bps, 8).CopyTo(vOut.Slice(j * dec.CacheUvStride)); vDst.Slice(j * WebPConstants.Bps, Math.Min(8, vOut.Length)).CopyTo(vOut.Slice(j * dec.CacheUvStride));
} }
} }
} }
@ -579,6 +579,11 @@ namespace SixLabors.ImageSharp.Formats.WebP
yEnd -= extraYRows; yEnd -= extraYRows;
} }
if (yEnd > io.CropBottom)
{
yEnd = io.CropBottom; // make sure we don't overflow on last row.
}
if (yStart < yEnd) if (yStart < yEnd)
{ {
io.Y = io.Y.Slice(io.CropLeft); io.Y = io.Y.Slice(io.CropLeft);
@ -791,7 +796,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
else else
{ {
left.NoneZeroAcDcCoeffs = macroBlock.NoneZeroAcDcCoeffs = 0; left.NoneZeroAcDcCoeffs = macroBlock.NoneZeroAcDcCoeffs = 0;
if (blockData.IsI4x4) if (!blockData.IsI4x4)
{ {
left.NoneZeroDcCoeffs = macroBlock.NoneZeroDcCoeffs = 0; left.NoneZeroDcCoeffs = macroBlock.NoneZeroDcCoeffs = 0;
} }
@ -917,8 +922,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
block.NonZeroUv = nonZeroUv; block.NonZeroUv = nonZeroUv;
// We look at the mode-code of each block and check if some blocks have less // We look at the mode-code of each block and check if some blocks have less
// than three non-zero coeffs (code < 2). This is to avoid dithering flat and // than three non-zero coeffs (code < 2). This is to avoid dithering flat and empty blocks.
// empty blocks.
block.Dither = (byte)((nonZeroUv & 0xaaaa) > 0 ? 0 : q.Dither); block.Dither = (byte)((nonZeroUv & 0xaaaa) > 0 ? 0 : q.Dither);
return (nonZeroY | nonZeroUv) is 0; return (nonZeroY | nonZeroUv) is 0;
@ -1161,8 +1165,8 @@ namespace SixLabors.ImageSharp.Formats.WebP
int startIdx = (int)this.bitReader.PartitionLength; int startIdx = (int)this.bitReader.PartitionLength;
Span<byte> sz = this.bitReader.Data.AsSpan(startIdx); Span<byte> sz = this.bitReader.Data.AsSpan(startIdx);
int sizeLeft = (int)size; int sizeLeft = (int)size;
int numPartsMinusOne = (1 << (int)this.bitReader.ReadValue(2)) - 1; dec.NumPartsMinusOne = (1 << (int)this.bitReader.ReadValue(2)) - 1;
int lastPart = numPartsMinusOne; int lastPart = dec.NumPartsMinusOne;
int partStart = startIdx + (lastPart * 3); int partStart = startIdx + (lastPart * 3);
sizeLeft -= lastPart * 3; sizeLeft -= lastPart * 3;

Loading…
Cancel
Save