Browse Source

Move alpha decoding related methods into the AlphaDecoder class

pull/1552/head
Brian Popow 6 years ago
parent
commit
d14b9819a5
  1. 93
      src/ImageSharp/Formats/WebP/AlphaDecoder.cs
  2. 2
      src/ImageSharp/Formats/WebP/LosslessUtils.cs
  3. 95
      src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs

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

@ -5,7 +5,7 @@ using System;
using System.Buffers;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.WebP
@ -98,8 +98,6 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// </summary>
public IMemoryOwner<byte> Alpha { get; }
public int CropTop { get; }
/// <summary>
/// Gets a value indicating whether the alpha channel uses compression.
/// </summary>
@ -218,6 +216,34 @@ namespace SixLabors.ImageSharp.Formats.WebP
this.PrevRow = lastRow - 1;
}
public void ExtractPalettedAlphaRows(int lastRow)
{
// For vertical and gradient filtering, we need to decode the part above the
// cropTop row, in order to have the correct spatial predictors.
int topRow = (this.AlphaFilterType is WebPAlphaFilterType.None || this.AlphaFilterType is WebPAlphaFilterType.Horizontal) ? 0 : this.LastRow;
int firstRow = (this.LastRow < topRow) ? topRow : this.LastRow;
if (lastRow > firstRow)
{
// Special method for paletted alpha data.
Span<byte> output = this.Alpha.Memory.Span;
Span<uint> pixelData = this.Vp8LDec.Pixels.Memory.Span;
Span<byte> pixelDataAsBytes = MemoryMarshal.Cast<uint, byte>(pixelData);
Span<byte> dst = output.Slice(this.Width * firstRow);
Span<byte> input = pixelDataAsBytes.Slice(this.Vp8LDec.Width * firstRow);
if (this.Vp8LDec.Transforms.Count is 0 || this.Vp8LDec.Transforms[0].TransformType != Vp8LTransformType.ColorIndexingTransform)
{
WebPThrowHelper.ThrowImageFormatException("error while decoding alpha channel, expected color index transform data is missing");
}
Vp8LTransform transform = this.Vp8LDec.Transforms[0];
ColorIndexInverseTransformAlpha(transform, firstRow, lastRow, input, dst);
this.AlphaApplyFilter(firstRow, lastRow, dst, this.Width);
}
this.LastRow = lastRow;
}
/// <summary>
/// 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>
@ -237,6 +263,46 @@ namespace SixLabors.ImageSharp.Formats.WebP
ExtractGreen(input, output, pixelCount);
}
private static void ColorIndexInverseTransformAlpha(
Vp8LTransform transform,
int yStart,
int yEnd,
Span<byte> src,
Span<byte> dst)
{
int bitsPerPixel = 8 >> transform.Bits;
int width = transform.XSize;
Span<uint> colorMap = transform.Data.Memory.Span;
int srcOffset = 0;
int dstOffset = 0;
if (bitsPerPixel < 8)
{
int pixelsPerByte = 1 << transform.Bits;
int countMask = pixelsPerByte - 1;
int bitMask = (1 << bitsPerPixel) - 1;
for (int y = yStart; y < yEnd; ++y)
{
int packedPixels = 0;
for (int x = 0; x < width; ++x)
{
if ((x & countMask) is 0)
{
packedPixels = src[srcOffset];
srcOffset++;
}
dst[dstOffset] = GetAlphaValue((int)colorMap[packedPixels & bitMask]);
dstOffset++;
packedPixels >>= bitsPerPixel;
}
}
}
else
{
MapAlpha(src, colorMap, dst, yStart, yEnd, width);
}
}
private static void HorizontalUnfilter(Span<byte> prev, Span<byte> input, Span<byte> dst, int width)
{
byte pred = (byte)(prev == null ? 0 : prev[0]);
@ -290,7 +356,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
/// transform (color indexing), and trivial non-green literals.
/// </summary>
/// <param name="hdr">The VP8L meta data.</param>
/// <returns>True, if alpha channel has one byte per pixel, otherwise 4.</returns>
/// <returns>True, if alpha channel needs one byte per pixel, otherwise 4.</returns>
private static bool Is8BOptimizable(Vp8LMetadata hdr)
{
if (hdr.ColorCacheSize > 0)
@ -322,6 +388,25 @@ namespace SixLabors.ImageSharp.Formats.WebP
return true;
}
private static void MapAlpha(Span<byte> src, Span<uint> colorMap, Span<byte> dst, int yStart, int yEnd, int width)
{
int offset = 0;
for (int y = yStart; y < yEnd; ++y)
{
for (int x = 0; x < width; ++x)
{
dst[offset] = GetAlphaValue((int)colorMap[src[offset]]);
offset++;
}
}
}
[MethodImpl(InliningOptions.ShortMethod)]
private static byte GetAlphaValue(int val)
{
return (byte)((val >> 8) & 0xff);
}
[MethodImpl(InliningOptions.ShortMethod)]
private static int GradientPredictor(byte a, byte b, byte c)
{

2
src/ImageSharp/Formats/WebP/LosslessUtils.cs

@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
/// <summary>
/// If there are not many unique pixel values, it may be more efficient to create a color index array and replace the pixel values by the array's indices.
/// If there are not many unique pixel values, it is more efficient to create a color index array and replace the pixel values by the array's indices.
/// This will reverse the color index transform.
/// </summary>
/// <param name="transform">The transform data contains color table size and the entries in the color table.</param>

95
src/ImageSharp/Formats/WebP/WebPLosslessDecoder.cs

@ -745,7 +745,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
++row;
if (row <= lastRow && (row % WebPConstants.NumArgbCacheRows is 0))
{
this.ExtractPalettedAlphaRows(dec, row);
dec.ExtractPalettedAlphaRows(row);
}
}
}
@ -775,7 +775,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
++row;
if (row <= lastRow && (row % WebPConstants.NumArgbCacheRows is 0))
{
this.ExtractPalettedAlphaRows(dec, row);
dec.ExtractPalettedAlphaRows(row);
}
}
@ -793,90 +793,7 @@ namespace SixLabors.ImageSharp.Formats.WebP
}
// Process the remaining rows corresponding to last row-block.
this.ExtractPalettedAlphaRows(dec, row > lastRow ? lastRow : row);
}
private void ExtractPalettedAlphaRows(AlphaDecoder dec, int lastRow)
{
// For vertical and gradient filtering, we need to decode the part above the
// cropTop row, in order to have the correct spatial predictors.
int topRow = (dec.AlphaFilterType is WebPAlphaFilterType.None || dec.AlphaFilterType is WebPAlphaFilterType.Horizontal)
? dec.CropTop
: dec.LastRow;
int firstRow = (dec.LastRow < topRow) ? topRow : dec.LastRow;
if (lastRow > firstRow)
{
// Special method for paletted alpha data.
Span<byte> output = dec.Alpha.Memory.Span;
Span<uint> pixelData = dec.Vp8LDec.Pixels.Memory.Span;
Span<byte> pixelDataAsBytes = MemoryMarshal.Cast<uint, byte>(pixelData);
Span<byte> dst = output.Slice(dec.Width * firstRow);
Span<byte> input = pixelDataAsBytes.Slice(dec.Vp8LDec.Width * firstRow);
if (dec.Vp8LDec.Transforms.Count is 0 || dec.Vp8LDec.Transforms[0].TransformType != Vp8LTransformType.ColorIndexingTransform)
{
WebPThrowHelper.ThrowImageFormatException("error while decoding alpha channel, expected color index transform data is missing");
}
Vp8LTransform transform = dec.Vp8LDec.Transforms[0];
this.ColorIndexInverseTransformAlpha(transform, firstRow, lastRow, input, dst);
dec.AlphaApplyFilter(firstRow, lastRow, dst, dec.Width);
}
dec.LastRow = lastRow;
}
private void ColorIndexInverseTransformAlpha(
Vp8LTransform transform,
int yStart,
int yEnd,
Span<byte> src,
Span<byte> dst)
{
int bitsPerPixel = 8 >> transform.Bits;
int width = transform.XSize;
Span<uint> colorMap = transform.Data.Memory.Span;
int srcOffset = 0;
int dstOffset = 0;
if (bitsPerPixel < 8)
{
int pixelsPerByte = 1 << transform.Bits;
int countMask = pixelsPerByte - 1;
int bitMask = (1 << bitsPerPixel) - 1;
for (int y = yStart; y < yEnd; ++y)
{
int packedPixels = 0;
for (int x = 0; x < width; ++x)
{
if ((x & countMask) is 0)
{
packedPixels = src[srcOffset];
srcOffset++;
}
dst[dstOffset] = GetAlphaValue((int)colorMap[packedPixels & bitMask]);
dstOffset++;
packedPixels >>= bitsPerPixel;
}
}
}
else
{
MapAlpha(src, colorMap, dst, yStart, yEnd, width);
}
}
private static void MapAlpha(Span<byte> src, Span<uint> colorMap, Span<byte> dst, int yStart, int yEnd, int width)
{
int offset = 0;
for (int y = yStart; y < yEnd; ++y)
{
for (int x = 0; x < width; ++x)
{
dst[offset] = GetAlphaValue((int)colorMap[src[offset]]);
offset++;
}
}
dec.ExtractPalettedAlphaRows(row > lastRow ? lastRow : row);
}
private void UpdateDecoder(Vp8LDecoder decoder, int width, int height)
@ -1048,11 +965,5 @@ namespace SixLabors.ImageSharp.Formats.WebP
huff.Value |= hCode.Value << shift;
return hCode.BitsUsed;
}
[MethodImpl(InliningOptions.ShortMethod)]
private static byte GetAlphaValue(int val)
{
return (byte)((val >> 8) & 0xff);
}
}
}

Loading…
Cancel
Save