Esempio n. 1
0
        /// <summary>
        /// Reads the frame indices marking the color to use for each pixel.
        /// </summary>
        /// <param name="imageDescriptor">The <see cref="GifImageDescriptor"/>.</param>
        /// <returns>The <see cref="T:byte[]"/></returns>
        private byte[] ReadFrameIndices(GifImageDescriptor imageDescriptor)
        {
            int dataSize = this.currentStream.ReadByte();

            byte[] indices;
            using (LzwDecoder lzwDecoder = new LzwDecoder(this.currentStream))
            {
                indices = lzwDecoder.DecodePixels(imageDescriptor.Width, imageDescriptor.Height, dataSize);
            }

            return(indices);
        }
Esempio n. 2
0
        /// <summary>
        /// Reads the local color table from the current frame.
        /// </summary>
        /// <param name="imageDescriptor">The <see cref="GifImageDescriptor"/>.</param>
        /// <returns>The <see cref="T:byte[]"/></returns>
        private byte[] ReadFrameLocalColorTable(GifImageDescriptor imageDescriptor)
        {
            byte[] localColorTable = null;

            if (imageDescriptor.LocalColorTableFlag)
            {
                localColorTable = new byte[imageDescriptor.LocalColorTableSize * 3];

                this.currentStream.Read(localColorTable, 0, localColorTable.Length);
            }

            return(localColorTable);
        }
Esempio n. 3
0
        /// <summary>
        /// Reads an individual gif frame.
        /// </summary>
        private void ReadFrame()
        {
            GifImageDescriptor imageDescriptor = this.ReadImageDescriptor();

            byte[] localColorTable = this.ReadFrameLocalColorTable(imageDescriptor);

            byte[] indices = this.ReadFrameIndices(imageDescriptor);

            // Determine the color table for this frame. If there is a local one, use it
            // otherwise use the global color table.
            byte[] colorTable = localColorTable ?? this.globalColorTable;

            this.ReadFrameColors(indices, colorTable, imageDescriptor);

            // Skip any remaining blocks
            this.Skip(0);
        }
Esempio n. 4
0
        /// <summary>
        /// Reads the image descriptor
        /// </summary>
        /// <returns><see cref="GifImageDescriptor"/></returns>
        private GifImageDescriptor ReadImageDescriptor()
        {
            this.currentStream.Read(this.buffer, 0, 9);

            byte packed = this.buffer[8];

            var imageDescriptor = new GifImageDescriptor
            {
                Left   = BitConverter.ToInt16(this.buffer, 0),
                Top    = BitConverter.ToInt16(this.buffer, 2),
                Width  = BitConverter.ToInt16(this.buffer, 4),
                Height = BitConverter.ToInt16(this.buffer, 6),
                LocalColorTableFlag = ((packed & 0x80) >> 7) == 1,
                LocalColorTableSize = 2 << (packed & 0x07),
                    InterlaceFlag   = ((packed & 0x40) >> 6) == 1
            };

            return(imageDescriptor);
        }
Esempio n. 5
0
        /// <summary>
        /// Reads an individual gif frame.
        /// </summary>
        private void ReadFrame()
        {
            GifImageDescriptor imageDescriptor = this.ReadImageDescriptor();

            byte[] localColorTable = null;
            byte[] indices         = null;
            try
            {
                // Determine the color table for this frame. If there is a local one, use it otherwise use the global color table.
                int length = this.globalColorTableLength;
                if (imageDescriptor.LocalColorTableFlag)
                {
                    length          = imageDescriptor.LocalColorTableSize * 3;
                    localColorTable = ArrayPool <byte> .Shared.Rent(length);

                    this.currentStream.Read(localColorTable, 0, length);
                }

                indices = ArrayPool <byte> .Shared.Rent(imageDescriptor.Width *imageDescriptor.Height);

                this.ReadFrameIndices(imageDescriptor, indices);
                this.ReadFrameColors(indices, localColorTable ?? this.globalColorTable, length, imageDescriptor);

                // Skip any remaining blocks
                this.Skip(0);
            }
            finally
            {
                if (localColorTable != null)
                {
                    ArrayPool <byte> .Shared.Return(localColorTable);
                }

                ArrayPool <byte> .Shared.Return(indices);
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Reads the frames colors, mapping indices to colors.
        /// </summary>
        /// <param name="indices">The indexed pixels.</param>
        /// <param name="colorTable">The color table containing the available colors.</param>
        /// <param name="descriptor">The <see cref="GifImageDescriptor"/></param>
        private unsafe void ReadFrameColors(byte[] indices, byte[] colorTable, GifImageDescriptor descriptor)
        {
            int imageWidth  = this.logicalScreenDescriptor.Width;
            int imageHeight = this.logicalScreenDescriptor.Height;

            ImageFrame <TColor, TPacked> previousFrame = null;

            ImageFrame <TColor, TPacked> currentFrame = null;

            ImageBase <TColor, TPacked> image;

            if (this.nextFrame == null)
            {
                image = this.decodedImage;

                image.Quality = colorTable.Length / 3;

                // This initializes the image to become fully transparent because the alpha channel is zero.
                image.InitPixels(imageWidth, imageHeight);
            }
            else
            {
                if (this.graphicsControlExtension != null &&
                    this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
                {
                    previousFrame = this.nextFrame;
                }

                currentFrame = this.nextFrame.Clone();

                image = currentFrame;

                this.RestoreToBackground(image);

                this.decodedImage.Frames.Add(currentFrame);
            }

            if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0)
            {
                image.FrameDelay = this.graphicsControlExtension.DelayTime;
            }

            int i                  = 0;
            int interlacePass      = 0; // The interlace pass
            int interlaceIncrement = 8; // The interlacing line increment
            int interlaceY         = 0; // The current interlaced line

            using (PixelAccessor <TColor, TPacked> pixelAccessor = image.Lock())
            {
                using (PixelArea <TColor, TPacked> pixelRow = new PixelArea <TColor, TPacked>(imageWidth, ComponentOrder.XYZW))
                {
                    for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++)
                    {
                        // Check if this image is interlaced.
                        int writeY; // the target y offset to write to
                        if (descriptor.InterlaceFlag)
                        {
                            // If so then we read lines at predetermined offsets.
                            // When an entire image height worth of offset lines has been read we consider this a pass.
                            // With each pass the number of offset lines changes and the starting line changes.
                            if (interlaceY >= descriptor.Height)
                            {
                                interlacePass++;
                                switch (interlacePass)
                                {
                                case 1:
                                    interlaceY = 4;
                                    break;

                                case 2:
                                    interlaceY         = 2;
                                    interlaceIncrement = 4;
                                    break;

                                case 3:
                                    interlaceY         = 1;
                                    interlaceIncrement = 2;
                                    break;
                                }
                            }

                            writeY = interlaceY + descriptor.Top;

                            interlaceY += interlaceIncrement;
                        }
                        else
                        {
                            writeY = y;
                        }

                        pixelRow.Reset();

                        byte *pixelBase = pixelRow.PixelBase;
                        for (int x = 0; x < descriptor.Width; x++)
                        {
                            int index = indices[i];

                            if (this.graphicsControlExtension == null ||
                                this.graphicsControlExtension.TransparencyFlag == false ||
                                this.graphicsControlExtension.TransparencyIndex != index)
                            {
                                int indexOffset = index * 3;
                                *(pixelBase + 0) = colorTable[indexOffset];
                                *(pixelBase + 1) = colorTable[indexOffset + 1];
                                *(pixelBase + 2) = colorTable[indexOffset + 2];
                                *(pixelBase + 3) = 255;
                            }

                            i++;
                            pixelBase += 4;
                        }

                        pixelAccessor.CopyFrom(pixelRow, writeY, descriptor.Left);
                    }
                }
            }

            if (previousFrame != null)
            {
                this.nextFrame = previousFrame;
                return;
            }

            if (currentFrame == null)
            {
                this.nextFrame = this.decodedImage.ToFrame();
            }
            else
            {
                this.nextFrame = currentFrame.Clone();
            }

            if (this.graphicsControlExtension != null &&
                this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground)
            {
                this.restoreArea = new Rectangle(descriptor.Left, descriptor.Top, descriptor.Width, descriptor.Height);
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Reads the frames colors, mapping indices to colors.
        /// </summary>
        /// <param name="indices">The indexed pixels.</param>
        /// <param name="colorTable">The color table containing the available colors.</param>
        /// <param name="colorTableLength">The color table length.</param>
        /// <param name="descriptor">The <see cref="GifImageDescriptor"/></param>
        private unsafe void ReadFrameColors(byte[] indices, byte[] colorTable, int colorTableLength, GifImageDescriptor descriptor)
        {
            int imageWidth  = this.logicalScreenDescriptor.Width;
            int imageHeight = this.logicalScreenDescriptor.Height;

            ImageFrame <TPixel> previousFrame = null;

            ImageFrame <TPixel> currentFrame = null;

            ImageBase <TPixel> image;

            if (this.previousFrame == null)
            {
                // This initializes the image to become fully transparent because the alpha channel is zero.
                this.image = new Image <TPixel>(this.configuration, imageWidth, imageHeight, this.metaData);

                this.SetFrameMetaData(this.metaData);

                image = this.image;
            }
            else
            {
                if (this.graphicsControlExtension != null &&
                    this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
                {
                    previousFrame = this.previousFrame;
                }

                currentFrame = this.previousFrame.Clone();

                this.SetFrameMetaData(currentFrame.MetaData);

                image = currentFrame;

                this.RestoreToBackground(image);

                this.image.Frames.Add(currentFrame);
            }

            int i                  = 0;
            int interlacePass      = 0; // The interlace pass
            int interlaceIncrement = 8; // The interlacing line increment
            int interlaceY         = 0; // The current interlaced line

            for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++)
            {
                // Check if this image is interlaced.
                int writeY; // the target y offset to write to
                if (descriptor.InterlaceFlag)
                {
                    // If so then we read lines at predetermined offsets.
                    // When an entire image height worth of offset lines has been read we consider this a pass.
                    // With each pass the number of offset lines changes and the starting line changes.
                    if (interlaceY >= descriptor.Height)
                    {
                        interlacePass++;
                        switch (interlacePass)
                        {
                        case 1:
                            interlaceY = 4;
                            break;

                        case 2:
                            interlaceY         = 2;
                            interlaceIncrement = 4;
                            break;

                        case 3:
                            interlaceY         = 1;
                            interlaceIncrement = 2;
                            break;
                        }
                    }

                    writeY = interlaceY + descriptor.Top;

                    interlaceY += interlaceIncrement;
                }
                else
                {
                    writeY = y;
                }

                Span <TPixel> rowSpan = image.GetRowSpan(writeY);

                Rgba32 rgba = new Rgba32(0, 0, 0, 255);

                for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++)
                {
                    int index = indices[i];

                    if (this.graphicsControlExtension == null ||
                        this.graphicsControlExtension.TransparencyFlag == false ||
                        this.graphicsControlExtension.TransparencyIndex != index)
                    {
                        int indexOffset = index * 3;

                        ref TPixel pixel = ref rowSpan[x];
                        rgba.Rgb = colorTable.GetRgb24(indexOffset);

                        pixel.PackFromRgba32(rgba);
                    }

                    i++;
                }
            }
        /// <summary>
        /// Reads the frames colors, mapping indices to colors.
        /// </summary>
        /// <param name="indices">The indexed pixels.</param>
        /// <param name="colorTable">The color table containing the available colors.</param>
        /// <param name="colorTableLength">The color table length.</param>
        /// <param name="descriptor">The <see cref="GifImageDescriptor"/></param>
        private unsafe void ReadFrameColors(byte[] indices, byte[] colorTable, int colorTableLength, GifImageDescriptor descriptor)
        {
            int imageWidth  = this.logicalScreenDescriptor.Width;
            int imageHeight = this.logicalScreenDescriptor.Height;

            ImageFrame <TColor> previousFrame = null;

            ImageFrame <TColor> currentFrame = null;

            ImageBase <TColor> image;

            if (this.previousFrame == null)
            {
                this.decodedImage.MetaData.Quality = colorTableLength / 3;

                // This initializes the image to become fully transparent because the alpha channel is zero.
                this.decodedImage.InitPixels(imageWidth, imageHeight);

                this.SetFrameDelay(this.decodedImage.MetaData);

                image = this.decodedImage;
            }
            else
            {
                if (this.graphicsControlExtension != null &&
                    this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
                {
                    previousFrame = this.previousFrame;
                }

                currentFrame = this.previousFrame.Clone();

                this.SetFrameDelay(currentFrame.MetaData);

                image = currentFrame;

                this.RestoreToBackground(image);

                this.decodedImage.Frames.Add(currentFrame);
            }

            int i                  = 0;
            int interlacePass      = 0; // The interlace pass
            int interlaceIncrement = 8; // The interlacing line increment
            int interlaceY         = 0; // The current interlaced line

            using (PixelAccessor <TColor> pixelAccessor = image.Lock())
            {
                for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++)
                {
                    // Check if this image is interlaced.
                    int writeY; // the target y offset to write to
                    if (descriptor.InterlaceFlag)
                    {
                        // If so then we read lines at predetermined offsets.
                        // When an entire image height worth of offset lines has been read we consider this a pass.
                        // With each pass the number of offset lines changes and the starting line changes.
                        if (interlaceY >= descriptor.Height)
                        {
                            interlacePass++;
                            switch (interlacePass)
                            {
                            case 1:
                                interlaceY = 4;
                                break;

                            case 2:
                                interlaceY         = 2;
                                interlaceIncrement = 4;
                                break;

                            case 3:
                                interlaceY         = 1;
                                interlaceIncrement = 2;
                                break;
                            }
                        }

                        writeY = interlaceY + descriptor.Top;

                        interlaceY += interlaceIncrement;
                    }
                    else
                    {
                        writeY = y;
                    }

                    for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++)
                    {
                        int index = indices[i];

                        if (this.graphicsControlExtension == null ||
                            this.graphicsControlExtension.TransparencyFlag == false ||
                            this.graphicsControlExtension.TransparencyIndex != index)
                        {
                            int indexOffset = index * 3;

                            TColor pixel = default(TColor);
                            pixel.PackFromBytes(colorTable[indexOffset], colorTable[indexOffset + 1], colorTable[indexOffset + 2], 255);
                            pixelAccessor[x, writeY] = pixel;
                        }

                        i++;
                    }
                }
            }

            if (previousFrame != null)
            {
                this.previousFrame = previousFrame;
                return;
            }

            this.previousFrame = currentFrame == null?this.decodedImage.ToFrame() : currentFrame;

            if (this.graphicsControlExtension != null &&
                this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground)
            {
                this.restoreArea = new Rectangle(descriptor.Left, descriptor.Top, descriptor.Width, descriptor.Height);
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Reads the frames colors, mapping indices to colors.
        /// </summary>
        /// <param name="indices">The indexed pixels.</param>
        /// <param name="colorTable">The color table containing the available colors.</param>
        /// <param name="descriptor">The <see cref="GifImageDescriptor"/></param>
        private void ReadFrameColors(byte[] indices, byte[] colorTable, GifImageDescriptor descriptor)
        {
            int imageWidth  = this.logicalScreenDescriptor.Width;
            int imageHeight = this.logicalScreenDescriptor.Height;

            if (this.currentFrame == null)
            {
                this.currentFrame = new TColor[imageWidth * imageHeight];
            }

            TColor[] lastFrame = null;

            if (this.graphicsControlExtension != null &&
                this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
            {
                lastFrame = new TColor[imageWidth * imageHeight];

                Array.Copy(this.currentFrame, lastFrame, lastFrame.Length);
            }

            int offset, i = 0;
            int interlacePass      = 0; // The interlace pass
            int interlaceIncrement = 8; // The interlacing line increment
            int interlaceY         = 0; // The current interlaced line

            for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++)
            {
                // Check if this image is interlaced.
                int writeY; // the target y offset to write to
                if (descriptor.InterlaceFlag)
                {
                    // If so then we read lines at predetermined offsets.
                    // When an entire image height worth of offset lines has been read we consider this a pass.
                    // With each pass the number of offset lines changes and the starting line changes.
                    if (interlaceY >= descriptor.Height)
                    {
                        interlacePass++;
                        switch (interlacePass)
                        {
                        case 1:
                            interlaceY = 4;
                            break;

                        case 2:
                            interlaceY         = 2;
                            interlaceIncrement = 4;
                            break;

                        case 3:
                            interlaceY         = 1;
                            interlaceIncrement = 2;
                            break;
                        }
                    }

                    writeY = interlaceY + descriptor.Top;

                    interlaceY += interlaceIncrement;
                }
                else
                {
                    writeY = y;
                }

                for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++)
                {
                    offset = (writeY * imageWidth) + x;
                    int index = indices[i];

                    if (this.graphicsControlExtension == null ||
                        this.graphicsControlExtension.TransparencyFlag == false ||
                        this.graphicsControlExtension.TransparencyIndex != index)
                    {
                        // Stored in r-> g-> b-> a order.
                        int    indexOffset = index * 3;
                        TColor pixel       = default(TColor);
                        pixel.PackFromVector4(new Color(colorTable[indexOffset], colorTable[indexOffset + 1], colorTable[indexOffset + 2]).ToVector4());
                        this.currentFrame[offset] = pixel;
                    }

                    i++;
                }
            }

            TColor[] pixels = new TColor[imageWidth * imageHeight];

            Array.Copy(this.currentFrame, pixels, pixels.Length);

            ImageBase <TColor, TPacked> currentImage;

            if (this.decodedImage.Pixels == null)
            {
                currentImage = this.decodedImage;
                currentImage.SetPixels(imageWidth, imageHeight, pixels);
                currentImage.Quality = colorTable.Length / 3;

                if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0)
                {
                    this.decodedImage.FrameDelay = this.graphicsControlExtension.DelayTime;
                }
            }
            else
            {
                ImageFrame <TColor, TPacked> frame = new ImageFrame <TColor, TPacked>();

                currentImage = frame;
                currentImage.SetPixels(imageWidth, imageHeight, pixels);
                currentImage.Quality = colorTable.Length / 3;

                if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0)
                {
                    currentImage.FrameDelay = this.graphicsControlExtension.DelayTime;
                }

                this.decodedImage.Frames.Add(frame);
            }

            if (this.graphicsControlExtension != null)
            {
                if (this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground)
                {
                    for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++)
                    {
                        for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++)
                        {
                            offset = (y * imageWidth) + x;

                            // Stored in r-> g-> b-> a order.
                            this.currentFrame[offset] = default(TColor);
                        }
                    }
                }
                else if (this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
                {
                    this.currentFrame = lastFrame;
                }
            }
        }