Skip to content

Commit

Permalink
Merge pull request #2823 from SixLabors/js/issue-2801
Browse files Browse the repository at this point in the history
WEBP : Use Correct Width With AlphaDecoder
  • Loading branch information
JimBobSquarePants authored Oct 22, 2024
2 parents f61cbe7 + 00b2152 commit 21ec18e
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 8 deletions.
7 changes: 4 additions & 3 deletions src/ImageSharp/Formats/Webp/AlphaDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,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);
}
}

Expand Down Expand Up @@ -257,14 +257,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.
/// </summary>
/// <param name="dec">The VP8L decoder.</param>
private void ExtractAlphaRows(Vp8LDecoder dec)
/// <param name="width">The image width.</param>
private void ExtractAlphaRows(Vp8LDecoder dec, int width)
{
int numRowsToProcess = dec.Height;
int width = dec.Width;
Span<uint> input = dec.Pixels.Memory.Span;
Span<byte> 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);
Expand Down
11 changes: 7 additions & 4 deletions src/ImageSharp/Formats/Webp/Lossless/LosslessUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,11 @@ private static void SubtractGreenFromBlueAndRedScalar(Span<uint> pixelData)
/// </summary>
/// <param name="transform">The transform data contains color table size and the entries in the color table.</param>
/// <param name="pixelData">The pixel data to apply the reverse transform on.</param>
public static void ColorIndexInverseTransform(Vp8LTransform transform, Span<uint> pixelData)
/// <param name="outputSpan">The resulting pixel data with the reversed transformation data.</param>
public static void ColorIndexInverseTransform(
Vp8LTransform transform,
Span<uint> pixelData,
Span<uint> outputSpan)
{
int bitsPerPixel = 8 >> transform.Bits;
int width = transform.XSize;
Expand All @@ -282,7 +286,6 @@ public static void ColorIndexInverseTransform(Vp8LTransform transform, Span<uint
int countMask = pixelsPerByte - 1;
int bitMask = (1 << bitsPerPixel) - 1;

uint[] decodedPixelData = new uint[width * height];
int pixelDataPos = 0;
for (int y = 0; y < height; y++)
{
Expand All @@ -298,12 +301,12 @@ public static void ColorIndexInverseTransform(Vp8LTransform transform, Span<uint
packedPixels = GetArgbIndex(pixelData[pixelDataPos++]);
}

decodedPixelData[decodedPixels++] = colorMap[(int)(packedPixels & bitMask)];
outputSpan[decodedPixels++] = colorMap[(int)(packedPixels & bitMask)];
packedPixels >>= bitsPerPixel;
}
}

decodedPixelData.AsSpan().CopyTo(pixelData);
outputSpan.CopyTo(pixelData);
}
else
{
Expand Down
7 changes: 6 additions & 1 deletion src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,7 @@ public static void ApplyInverseTransforms(Vp8LDecoder decoder, Span<uint> pixelD
List<Vp8LTransform> 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)
{
Expand All @@ -701,7 +702,11 @@ public static void ApplyInverseTransforms(Vp8LDecoder decoder, Span<uint> pixelD
LosslessUtils.ColorSpaceInverseTransform(transform, pixelData);
break;
case Vp8LTransformType.ColorIndexingTransform:
LosslessUtils.ColorIndexInverseTransform(transform, pixelData);
using (IMemoryOwner<uint> output = memoryAllocator.Allocate<uint>(transform.XSize * transform.YSize, AllocationOptions.Clean))
{
LosslessUtils.ColorIndexInverseTransform(transform, pixelData, output.GetSpan());
}

break;
}
}
Expand Down
15 changes: 15 additions & 0 deletions tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,21 @@ public void WebpDecoder_CanDecode_Issue2763<TPixel>(TestImageProvider<TPixel> 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<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
WebpEncoder encoder = new()
{
Quality = 100
};

using Image<TPixel> image = provider.GetImage();
image.VerifyEncoder(provider, "webp", string.Empty, encoder, ImageComparer.TolerantPercentage(0.0994F));
}

public static void RunEncodeLossy_WithPeakImage()
{
TestImageProvider<Rgba32> provider = TestImageProvider<Rgba32>.File(TestImageLossyFullPath);
Expand Down
1 change: 1 addition & 0 deletions tests/ImageSharp.Tests/TestImages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -827,6 +827,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";
}
}

Expand Down
3 changes: 3 additions & 0 deletions tests/Images/Input/Webp/issues/Issue2801.webp
Git LFS file not shown

0 comments on commit 21ec18e

Please sign in to comment.