Browse Source

Merge branch 'release/3.1.x' into js/issue-2806

pull/2828/head
James Jackson-South 2 years ago
parent
commit
ee535321e2
  1. 7
      src/ImageSharp/Formats/Webp/AlphaDecoder.cs
  2. 11
      src/ImageSharp/Formats/Webp/Lossless/LosslessUtils.cs
  3. 7
      src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs
  4. 15
      tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs
  5. 1
      tests/ImageSharp.Tests/TestImages.cs
  6. 3
      tests/Images/Input/Webp/issues/Issue2801.webp

7
src/ImageSharp/Formats/Webp/AlphaDecoder.cs

@ -181,7 +181,7 @@ internal class AlphaDecoder : IDisposable
else else
{ {
this.LosslessDecoder.DecodeImageData(this.Vp8LDec, this.Vp8LDec.Pixels.Memory.Span); this.LosslessDecoder.DecodeImageData(this.Vp8LDec, this.Vp8LDec.Pixels.Memory.Span);
this.ExtractAlphaRows(this.Vp8LDec); this.ExtractAlphaRows(this.Vp8LDec, this.Width);
} }
} }
@ -255,14 +255,15 @@ internal class AlphaDecoder : IDisposable
/// Once the image-stream is decoded into ARGB color values, the transparency information will be extracted from the green channel of the ARGB quadruplet. /// 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> /// </summary>
/// <param name="dec">The VP8L decoder.</param> /// <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 numRowsToProcess = dec.Height;
int width = dec.Width;
Span<uint> input = dec.Pixels.Memory.Span; Span<uint> input = dec.Pixels.Memory.Span;
Span<byte> output = this.Alpha.Memory.Span; Span<byte> output = this.Alpha.Memory.Span;
// Extract alpha (which is stored in the green plane). // Extract alpha (which is stored in the green plane).
// the final width (!= dec->width_)
int pixelCount = width * numRowsToProcess; int pixelCount = width * numRowsToProcess;
WebpLosslessDecoder.ApplyInverseTransforms(dec, input, this.memoryAllocator); WebpLosslessDecoder.ApplyInverseTransforms(dec, input, this.memoryAllocator);
ExtractGreen(input, output, pixelCount); ExtractGreen(input, output, pixelCount);

11
src/ImageSharp/Formats/Webp/Lossless/LosslessUtils.cs

@ -269,7 +269,11 @@ internal static unsafe class LosslessUtils
/// </summary> /// </summary>
/// <param name="transform">The transform data contains color table size and the entries in the color table.</param> /// <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> /// <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 bitsPerPixel = 8 >> transform.Bits;
int width = transform.XSize; int width = transform.XSize;
@ -282,7 +286,6 @@ internal static unsafe class LosslessUtils
int countMask = pixelsPerByte - 1; int countMask = pixelsPerByte - 1;
int bitMask = (1 << bitsPerPixel) - 1; int bitMask = (1 << bitsPerPixel) - 1;
uint[] decodedPixelData = new uint[width * height];
int pixelDataPos = 0; int pixelDataPos = 0;
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
@ -298,12 +301,12 @@ internal static unsafe class LosslessUtils
packedPixels = GetArgbIndex(pixelData[pixelDataPos++]); packedPixels = GetArgbIndex(pixelData[pixelDataPos++]);
} }
decodedPixelData[decodedPixels++] = colorMap[(int)(packedPixels & bitMask)]; outputSpan[decodedPixels++] = colorMap[(int)(packedPixels & bitMask)];
packedPixels >>= bitsPerPixel; packedPixels >>= bitsPerPixel;
} }
} }
decodedPixelData.AsSpan().CopyTo(pixelData); outputSpan.CopyTo(pixelData);
} }
else else
{ {

7
src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs

@ -684,6 +684,7 @@ internal sealed class WebpLosslessDecoder
List<Vp8LTransform> transforms = decoder.Transforms; List<Vp8LTransform> transforms = decoder.Transforms;
for (int i = transforms.Count - 1; i >= 0; i--) for (int i = transforms.Count - 1; i >= 0; i--)
{ {
// TODO: Review these 1D allocations. They could conceivably exceed limits.
Vp8LTransform transform = transforms[i]; Vp8LTransform transform = transforms[i];
switch (transform.TransformType) switch (transform.TransformType)
{ {
@ -701,7 +702,11 @@ internal sealed class WebpLosslessDecoder
LosslessUtils.ColorSpaceInverseTransform(transform, pixelData); LosslessUtils.ColorSpaceInverseTransform(transform, pixelData);
break; break;
case Vp8LTransformType.ColorIndexingTransform: case Vp8LTransformType.ColorIndexingTransform:
LosslessUtils.ColorIndexInverseTransform(transform, pixelData); using (IMemoryOwner<uint> output = memoryAllocator.Allocate<uint>(pixelData.Length, AllocationOptions.Clean))
{
LosslessUtils.ColorIndexInverseTransform(transform, pixelData, output.GetSpan());
}
break; break;
} }
} }

15
tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs

@ -514,6 +514,21 @@ public class WebpEncoderTests
image.VerifyEncoder(provider, "webp", string.Empty, encoder); 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() public static void RunEncodeLossy_WithPeakImage()
{ {
TestImageProvider<Rgba32> provider = TestImageProvider<Rgba32>.File(TestImageLossyFullPath); TestImageProvider<Rgba32> provider = TestImageProvider<Rgba32>.File(TestImageLossyFullPath);

1
tests/ImageSharp.Tests/TestImages.cs

@ -824,6 +824,7 @@ public static class TestImages
public const string Issue2257 = "Webp/issues/Issue2257.webp"; public const string Issue2257 = "Webp/issues/Issue2257.webp";
public const string Issue2670 = "Webp/issues/Issue2670.webp"; public const string Issue2670 = "Webp/issues/Issue2670.webp";
public const string Issue2763 = "Webp/issues/Issue2763.png"; public const string Issue2763 = "Webp/issues/Issue2763.png";
public const string Issue2801 = "Webp/issues/Issue2801.webp";
} }
} }

3
tests/Images/Input/Webp/issues/Issue2801.webp

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e90a0d853ddf70d823d8da44eb6c57081e955b1fb7f436a1fd88ca5e5c75a003
size 261212
Loading…
Cancel
Save