Browse Source

Add filtering for uncompressed alpha

pull/1552/head
Brian Popow 6 years ago
parent
commit
a75bb568ea
  1. 90
      src/ImageSharp/Formats/WebP/AlphaDecoder.cs
  2. 2
      tests/ImageSharp.Tests/Formats/WebP/WebPDecoderTests.cs

90
src/ImageSharp/Formats/WebP/AlphaDecoder.cs

@ -95,18 +95,33 @@ namespace SixLabors.ImageSharp.Formats.WebP
WebPThrowHelper.ThrowImageFormatException("not enough data in the ALPH chunk"); WebPThrowHelper.ThrowImageFormatException("not enough data in the ALPH chunk");
} }
switch (this.FilterType) if (this.FilterType == WebPFilterType.None)
{ {
case WebPFilterType.None: this.Data.AsSpan(0, this.Width * this.Height).CopyTo(this.Alpha);
this.Data.AsSpan(0, this.Width * this.Height).CopyTo(this.Alpha); return;
break; }
case WebPFilterType.Horizontal:
Span<byte> deltas = this.Data.AsSpan();
break; Span<byte> dst = this.Alpha.AsSpan();
case WebPFilterType.Vertical: Span<byte> prev = null;
break; for (int y = 0; y < this.Height; ++y)
case WebPFilterType.Gradient: {
break; switch (this.FilterType)
{
case WebPFilterType.Horizontal:
HorizontalUnfilter(prev, deltas, dst, this.Width);
break;
case WebPFilterType.Vertical:
VerticalUnfilter(prev, deltas, dst, this.Width);
break;
case WebPFilterType.Gradient:
GradientUnfilter(prev, deltas, dst, this.Width);
break;
}
prev = dst;
deltas = deltas.Slice(this.Width);
dst = dst.Slice(this.Width);
} }
} }
else else
@ -115,6 +130,59 @@ namespace SixLabors.ImageSharp.Formats.WebP
} }
} }
private static void HorizontalUnfilter(Span<byte> prev, Span<byte> input, Span<byte> dst, int width)
{
byte pred = (byte)(prev == null ? 0 : prev[0]);
for (int i = 0; i < width; ++i)
{
dst[i] = (byte)(pred + input[i]);
pred = dst[i];
}
}
private static void VerticalUnfilter(Span<byte> prev, Span<byte> input, Span<byte> dst, int width)
{
if (prev == null)
{
HorizontalUnfilter(null, input, dst, width);
}
else
{
for (int i = 0; i < width; ++i)
{
dst[i] = (byte)(prev[i] + input[i]);
}
}
}
private static void GradientUnfilter(Span<byte> prev, Span<byte> input, Span<byte> dst, int width)
{
if (prev == null)
{
HorizontalUnfilter(null, input, dst, width);
}
else
{
byte top = prev[0];
byte topLeft = top;
byte left = top;
for (int i = 0; i < width; ++i)
{
top = prev[i];
left = (byte)(input[i] + GradientPredictor(left, top, topLeft));
topLeft = top;
dst[i] = left;
}
}
}
private static int GradientPredictor(byte a, byte b, byte c)
{
int g = a + b - c;
return ((g & ~0xff) is 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit
}
// Taken from vp8l_dec.c AlphaApplyFilter // Taken from vp8l_dec.c AlphaApplyFilter
public void AlphaApplyFilter( public void AlphaApplyFilter(
int firstRow, int firstRow,

2
tests/ImageSharp.Tests/Formats/WebP/WebPDecoderTests.cs

@ -173,6 +173,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP
[WithFile(Lossy.AlphaNoCompressionNoFilter, PixelTypes.Rgba32)] [WithFile(Lossy.AlphaNoCompressionNoFilter, PixelTypes.Rgba32)]
[WithFile(Lossy.AlphaCompressedNoFilter, PixelTypes.Rgba32)] [WithFile(Lossy.AlphaCompressedNoFilter, PixelTypes.Rgba32)]
[WithFile(Lossy.AlphaNoCompressionHorizontalFilter, PixelTypes.Rgba32)] [WithFile(Lossy.AlphaNoCompressionHorizontalFilter, PixelTypes.Rgba32)]
[WithFile(Lossy.AlphaNoCompressionVerticalFilter, PixelTypes.Rgba32)]
[WithFile(Lossy.AlphaNoCompressionGradientFilter, PixelTypes.Rgba32)]
public void WebpDecoder_CanDecode_Lossy_WithAlpha<TPixel>(TestImageProvider<TPixel> provider) public void WebpDecoder_CanDecode_Lossy_WithAlpha<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {

Loading…
Cancel
Save