Example #1
0
        /// <summary>
        /// A Webp lossless image can go through four different types of transformation before being entropy encoded.
        /// This will reverse the transformations, if any are present.
        /// </summary>
        /// <param name="decoder">The decoder holding the transformation infos.</param>
        /// <param name="pixelData">The pixel data to apply the transformation.</param>
        /// <param name="memoryAllocator">The memory allocator is needed to allocate memory during the predictor transform.</param>
        public static void ApplyInverseTransforms(Vp8LDecoder decoder, Span <uint> pixelData, MemoryAllocator memoryAllocator)
        {
            List <Vp8LTransform> transforms = decoder.Transforms;

            for (int i = transforms.Count - 1; i >= 0; i--)
            {
                Vp8LTransform     transform     = transforms[i];
                Vp8LTransformType transformType = transform.TransformType;
                switch (transformType)
                {
                case Vp8LTransformType.PredictorTransform:
                    using (IMemoryOwner <uint> output = memoryAllocator.Allocate <uint>(pixelData.Length, AllocationOptions.Clean))
                    {
                        LosslessUtils.PredictorInverseTransform(transform, pixelData, output.GetSpan());
                    }

                    break;

                case Vp8LTransformType.SubtractGreen:
                    LosslessUtils.AddGreenToBlueAndRed(pixelData);
                    break;

                case Vp8LTransformType.CrossColorTransform:
                    LosslessUtils.ColorSpaceInverseTransform(transform, pixelData);
                    break;

                case Vp8LTransformType.ColorIndexingTransform:
                    LosslessUtils.ColorIndexInverseTransform(transform, pixelData);
                    break;
                }
            }
        }
Example #2
0
        /// <summary>
        /// Reads the transformations, if any are present.
        /// </summary>
        /// <param name="xSize">The width of the image.</param>
        /// <param name="ySize">The height of the image.</param>
        /// <param name="decoder">Vp8LDecoder where the transformations will be stored.</param>
        private void ReadTransformation(int xSize, int ySize, Vp8LDecoder decoder)
        {
            var transformType = (Vp8LTransformType)this.bitReader.ReadValue(2);
            var transform     = new Vp8LTransform(transformType, xSize, ySize);

            // Each transform is allowed to be used only once.
            foreach (Vp8LTransform decoderTransform in decoder.Transforms)
            {
                if (decoderTransform.TransformType == transform.TransformType)
                {
                    WebpThrowHelper.ThrowImageFormatException("Each transform can only be present once");
                }
            }

            switch (transformType)
            {
            case Vp8LTransformType.SubtractGreen:
                // There is no data associated with this transform.
                break;

            case Vp8LTransformType.ColorIndexingTransform:
                // The transform data contains color table size and the entries in the color table.
                // 8 bit value for color table size.
                uint numColors = this.bitReader.ReadValue(8) + 1;
                int  bits      = numColors > 16 ? 0
                                     : numColors > 4 ? 1
                                     : numColors > 2 ? 2
                                     : 3;
                transform.Bits = bits;
                using (IMemoryOwner <uint> colorMap = this.DecodeImageStream(decoder, (int)numColors, 1, false))
                {
                    int finalNumColors = 1 << (8 >> transform.Bits);
                    IMemoryOwner <uint> newColorMap = this.memoryAllocator.Allocate <uint>(finalNumColors, AllocationOptions.Clean);
                    LosslessUtils.ExpandColorMap((int)numColors, colorMap.GetSpan(), newColorMap.GetSpan());
                    transform.Data = newColorMap;
                }

                break;

            case Vp8LTransformType.PredictorTransform:
            case Vp8LTransformType.CrossColorTransform:
            {
                // The first 3 bits of prediction data define the block width and height in number of bits.
                transform.Bits = (int)this.bitReader.ReadValue(3) + 2;
                int blockWidth  = LosslessUtils.SubSampleSize(transform.XSize, transform.Bits);
                int blockHeight = LosslessUtils.SubSampleSize(transform.YSize, transform.Bits);
                IMemoryOwner <uint> transformData = this.DecodeImageStream(decoder, blockWidth, blockHeight, false);
                transform.Data = transformData;
                break;
            }
            }

            decoder.Transforms.Add(transform);
        }