Esempio n. 1
0
        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;
        }
Esempio n. 2
0
        /// <summary>
        /// Decodes and filters the maybe compressed alpha data.
        /// </summary>
        public void Decode()
        {
            if (!this.Compressed)
            {
                Span <byte> dataSpan   = this.Data.Memory.Span;
                int         pixelCount = this.Width * this.Height;
                if (dataSpan.Length < pixelCount)
                {
                    WebpThrowHelper.ThrowImageFormatException("not enough data in the ALPH chunk");
                }

                Span <byte> alphaSpan = this.Alpha.Memory.Span;
                if (this.AlphaFilterType == WebpAlphaFilterType.None)
                {
                    dataSpan.Slice(0, pixelCount).CopyTo(alphaSpan);
                    return;
                }

                Span <byte> deltas = dataSpan;
                Span <byte> dst    = alphaSpan;
                Span <byte> prev   = default;
                for (int y = 0; y < this.Height; y++)
                {
                    switch (this.AlphaFilterType)
                    {
                    case WebpAlphaFilterType.Horizontal:
                        HorizontalUnfilter(prev, deltas, dst, this.Width);
                        break;

                    case WebpAlphaFilterType.Vertical:
                        VerticalUnfilter(prev, deltas, dst, this.Width);
                        break;

                    case WebpAlphaFilterType.Gradient:
                        GradientUnfilter(prev, deltas, dst, this.Width);
                        break;
                    }

                    prev   = dst;
                    deltas = deltas.Slice(this.Width);
                    dst    = dst.Slice(this.Width);
                }
            }
            else
            {
                if (this.Use8BDecode)
                {
                    this.LosslessDecoder.DecodeAlphaData(this);
                }
                else
                {
                    this.LosslessDecoder.DecodeImageData(this.Vp8LDec, this.Vp8LDec.Pixels.Memory.Span);
                    this.ExtractAlphaRows(this.Vp8LDec);
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="AlphaDecoder"/> class.
        /// </summary>
        /// <param name="width">The width of the image.</param>
        /// <param name="height">The height of the image.</param>
        /// <param name="data">The (maybe compressed) alpha data.</param>
        /// <param name="alphaChunkHeader">The first byte of the alpha image stream contains information on how to decode the stream.</param>
        /// <param name="memoryAllocator">Used for allocating memory during decoding.</param>
        /// <param name="configuration">The configuration.</param>
        public AlphaDecoder(int width, int height, IMemoryOwner <byte> data, byte alphaChunkHeader, MemoryAllocator memoryAllocator, Configuration configuration)
        {
            this.Width           = width;
            this.Height          = height;
            this.Data            = data;
            this.memoryAllocator = memoryAllocator;
            this.LastRow         = 0;
            int totalPixels = width * height;

            var compression = (WebpAlphaCompressionMethod)(alphaChunkHeader & 0x03);

            if (compression is not WebpAlphaCompressionMethod.NoCompression and not WebpAlphaCompressionMethod.WebpLosslessCompression)
            {
                WebpThrowHelper.ThrowImageFormatException($"unexpected alpha compression method {compression} found");
            }

            this.Compressed = compression == WebpAlphaCompressionMethod.WebpLosslessCompression;

            // The filtering method used. Only values between 0 and 3 are valid.
            int filter = (alphaChunkHeader >> 2) & 0x03;

            if (filter is < (int)WebpAlphaFilterType.None or > (int)WebpAlphaFilterType.Gradient)
            {
                WebpThrowHelper.ThrowImageFormatException($"unexpected alpha filter method {filter} found");
            }

            this.Alpha           = memoryAllocator.Allocate <byte>(totalPixels);
            this.AlphaFilterType = (WebpAlphaFilterType)filter;
            this.Vp8LDec         = new Vp8LDecoder(width, height, memoryAllocator);

            if (this.Compressed)
            {
                var bitReader = new Vp8LBitReader(data);
                this.LosslessDecoder = new WebpLosslessDecoder(bitReader, memoryAllocator, configuration);
                this.LosslessDecoder.DecodeImageStream(this.Vp8LDec, width, height, true);
                this.Use8BDecode = this.Vp8LDec.Transforms.Count > 0 && Is8BOptimizable(this.Vp8LDec.Metadata);
            }
        }