Exemplo n.º 1
0
        /// <summary>
        /// Converts the 8x8 region of the image whose top-left corner is x,y to its YCbCr values.
        /// </summary>
        /// <typeparam name="TColor">The pixel format.</typeparam>
        /// <param name="pixels">The pixel accessor.</param>
        /// <param name="x">The x-position within the image.</param>
        /// <param name="y">The y-position within the image.</param>
        /// <param name="yBlock">The luminance block.</param>
        /// <param name="cbBlock">The red chroma block.</param>
        /// <param name="crBlock">The blue chroma block.</param>
        /// <param name="rgbBytes">Temporal <see cref="PixelArea{TColor}"/> provided by the caller</param>
        private static void ToYCbCr <TColor>(
            PixelAccessor <TColor> pixels,
            int x,
            int y,
            Block8x8F *yBlock,
            Block8x8F *cbBlock,
            Block8x8F *crBlock,
            PixelArea <TColor> rgbBytes)
            where TColor : struct, IPackedPixel, IEquatable <TColor>
        {
            float *yBlockRaw  = (float *)yBlock;
            float *cbBlockRaw = (float *)cbBlock;
            float *crBlockRaw = (float *)crBlock;

            rgbBytes.Reset();
            pixels.CopyRGBBytesStretchedTo(rgbBytes, y, x);

            byte *data = (byte *)rgbBytes.DataPointer;

            for (int j = 0; j < 8; j++)
            {
                int j8 = j * 8;
                for (int i = 0; i < 8; i++)
                {
                    // Convert returned bytes into the YCbCr color space. Assume RGBA
                    int r = data[0];
                    int g = data[1];
                    int b = data[2];

                    // Speed up the algorithm by removing floating point calculation
                    // Scale by 65536, add .5F and truncate value. We use bit shifting to divide the result
                    int y0 = 19595 * r;   // (0.299F * 65536) + .5F
                    int y1 = 38470 * g;   // (0.587F * 65536) + .5F
                    int y2 = 7471 * b;    // (0.114F * 65536) + .5F

                    int cb0 = -11057 * r; // (-0.168736F * 65536) + .5F
                    int cb1 = 21710 * g;  // (0.331264F * 65536) + .5F
                    int cb2 = 32768 * b;  // (0.5F * 65536) + .5F

                    int cr0 = 32768 * r;  // (0.5F * 65536) + .5F
                    int cr1 = 27439 * g;  // (0.418688F * 65536) + .5F
                    int cr2 = 5329 * b;   // (0.081312F * 65536) + .5F

                    float yy = (y0 + y1 + y2) >> 16;
                    float cb = 128 + ((cb0 - cb1 + cb2) >> 16);
                    float cr = 128 + ((cr0 - cr1 - cr2) >> 16);

                    int index = j8 + i;

                    yBlockRaw[index]  = yy;
                    cbBlockRaw[index] = cb;
                    crBlockRaw[index] = cr;

                    data += 3;
                }
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Converts the 8x8 region of the image whose top-left corner is x,y to its YCbCr values.
        /// </summary>
        /// <typeparam name="TColor">The pixel format.</typeparam>
        /// <param name="pixels">The pixel accessor.</param>
        /// <param name="x">The x-position within the image.</param>
        /// <param name="y">The y-position within the image.</param>
        /// <param name="yBlock">The luminance block.</param>
        /// <param name="cbBlock">The red chroma block.</param>
        /// <param name="crBlock">The blue chroma block.</param>
        /// <param name="rgbBytes">Temporal <see cref="PixelArea{TColor}"/> provided by the caller</param>
        private static void ToYCbCr <TColor>(
            PixelAccessor <TColor> pixels,
            int x,
            int y,
            Block8x8F *yBlock,
            Block8x8F *cbBlock,
            Block8x8F *crBlock,
            PixelArea <TColor> rgbBytes)
            where TColor : struct, IPixel <TColor>
        {
            float *yBlockRaw  = (float *)yBlock;
            float *cbBlockRaw = (float *)cbBlock;
            float *crBlockRaw = (float *)crBlock;

            rgbBytes.Reset();
            pixels.CopyRGBBytesStretchedTo(rgbBytes, y, x);

            ref byte data0   = ref rgbBytes.Bytes[0];
Exemplo n.º 3
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);
            }
        }