diff --git a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs
index 63571617fb..ca419e619e 100644
--- a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs
+++ b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs
@@ -181,7 +181,7 @@ public void Decode()
else
{
this.LosslessDecoder.DecodeImageData(this.Vp8LDec, this.Vp8LDec.Pixels.Memory.Span);
- this.ExtractAlphaRows(this.Vp8LDec);
+ this.ExtractAlphaRows(this.Vp8LDec, this.Width);
}
}
@@ -255,14 +255,15 @@ public void ExtractPalettedAlphaRows(int lastRow)
/// Once the image-stream is decoded into ARGB color values, the transparency information will be extracted from the green channel of the ARGB quadruplet.
///
/// The VP8L decoder.
- private void ExtractAlphaRows(Vp8LDecoder dec)
+ /// The image width.
+ private void ExtractAlphaRows(Vp8LDecoder dec, int width)
{
int numRowsToProcess = dec.Height;
- int width = dec.Width;
Span input = dec.Pixels.Memory.Span;
Span output = this.Alpha.Memory.Span;
// Extract alpha (which is stored in the green plane).
+ // the final width (!= dec->width_)
int pixelCount = width * numRowsToProcess;
WebpLosslessDecoder.ApplyInverseTransforms(dec, input, this.memoryAllocator);
ExtractGreen(input, output, pixelCount);
diff --git a/src/ImageSharp/Formats/Webp/Lossless/LosslessUtils.cs b/src/ImageSharp/Formats/Webp/Lossless/LosslessUtils.cs
index 024adb7c23..5287f0b753 100644
--- a/src/ImageSharp/Formats/Webp/Lossless/LosslessUtils.cs
+++ b/src/ImageSharp/Formats/Webp/Lossless/LosslessUtils.cs
@@ -269,7 +269,11 @@ private static void SubtractGreenFromBlueAndRedScalar(Span pixelData)
///
/// The transform data contains color table size and the entries in the color table.
/// The pixel data to apply the reverse transform on.
- public static void ColorIndexInverseTransform(Vp8LTransform transform, Span pixelData)
+ /// The resulting pixel data with the reversed transformation data.
+ public static void ColorIndexInverseTransform(
+ Vp8LTransform transform,
+ Span pixelData,
+ Span outputSpan)
{
int bitsPerPixel = 8 >> transform.Bits;
int width = transform.XSize;
@@ -282,7 +286,6 @@ public static void ColorIndexInverseTransform(Vp8LTransform transform, Span>= bitsPerPixel;
}
}
- decodedPixelData.AsSpan().CopyTo(pixelData);
+ outputSpan.CopyTo(pixelData);
}
else
{
diff --git a/src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs b/src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs
index e4c2a7ddf6..0f366cb1e7 100644
--- a/src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs
+++ b/src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs
@@ -684,6 +684,7 @@ public static void ApplyInverseTransforms(Vp8LDecoder decoder, Span pixelD
List transforms = decoder.Transforms;
for (int i = transforms.Count - 1; i >= 0; i--)
{
+ // TODO: Review these 1D allocations. They could conceivably exceed limits.
Vp8LTransform transform = transforms[i];
switch (transform.TransformType)
{
@@ -701,7 +702,11 @@ public static void ApplyInverseTransforms(Vp8LDecoder decoder, Span pixelD
LosslessUtils.ColorSpaceInverseTransform(transform, pixelData);
break;
case Vp8LTransformType.ColorIndexingTransform:
- LosslessUtils.ColorIndexInverseTransform(transform, pixelData);
+ using (IMemoryOwner output = memoryAllocator.Allocate(pixelData.Length, AllocationOptions.Clean))
+ {
+ LosslessUtils.ColorIndexInverseTransform(transform, pixelData, output.GetSpan());
+ }
+
break;
}
}
diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs
index d1d83ffb9a..031a9ba059 100644
--- a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs
@@ -514,6 +514,21 @@ public void WebpDecoder_CanDecode_Issue2763(TestImageProvider pr
image.VerifyEncoder(provider, "webp", string.Empty, encoder);
}
+ // https://github.com/SixLabors/ImageSharp/issues/2801
+ [Theory]
+ [WithFile(Lossy.Issue2801, PixelTypes.Rgba32)]
+ public void WebpDecoder_CanDecode_Issue2801(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ WebpEncoder encoder = new()
+ {
+ Quality = 100
+ };
+
+ using Image image = provider.GetImage();
+ image.VerifyEncoder(provider, "webp", string.Empty, encoder, ImageComparer.TolerantPercentage(0.0994F));
+ }
+
public static void RunEncodeLossy_WithPeakImage()
{
TestImageProvider provider = TestImageProvider.File(TestImageLossyFullPath);
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index 847aac3478..a0e951e70d 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -824,6 +824,7 @@ public static class Lossy
public const string Issue2257 = "Webp/issues/Issue2257.webp";
public const string Issue2670 = "Webp/issues/Issue2670.webp";
public const string Issue2763 = "Webp/issues/Issue2763.png";
+ public const string Issue2801 = "Webp/issues/Issue2801.webp";
}
}
diff --git a/tests/Images/Input/Webp/issues/Issue2801.webp b/tests/Images/Input/Webp/issues/Issue2801.webp
new file mode 100644
index 0000000000..a3b5fee6e0
--- /dev/null
+++ b/tests/Images/Input/Webp/issues/Issue2801.webp
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e90a0d853ddf70d823d8da44eb6c57081e955b1fb7f436a1fd88ca5e5c75a003
+size 261212