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 or 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 == 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; }
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; if (bitsPerPixel < 8) { int srcOffset = 0; int dstOffset = 0; 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) == 0) { packedPixels = src[srcOffset]; srcOffset++; } dst[dstOffset] = GetAlphaValue((int)colorMap[packedPixels & bitMask]); dstOffset++; packedPixels >>= bitsPerPixel; } } } else { MapAlpha(src, colorMap, dst, yStart, yEnd, width); } }