Beispiel #1
0
 public GifFrame(Stream inputStream,
                 LogicalScreenDescriptor lsd,
                 ColourTable gct,
                 GraphicControlExtension gce,
                 GifFrame previousFrame,
                 GifFrame previousFrameBut1)
     : this(inputStream, lsd, gct, gce, previousFrame, previousFrameBut1, false)
 {
 }
Beispiel #2
0
        /// <summary>
        /// Gets the base image for this frame. This will be overpainted with
        /// the pixels for this frame, where they are not transparent.
        /// </summary>
        /// <param name="previousFrame">
        /// The frame which preceded this frame in the GIF stream.
        /// Null if this is the first frame in the stream.
        /// </param>
        /// <param name="previousFrameBut1">
        /// The frame which preceded the previous frame in the GIF stream.
        /// Null if this is the first or seond frame in the stream.
        /// </param>
        /// <param name="lsd">
        /// The logical screen descriptor for this GIF stream.
        /// </param>
        /// <param name="gce">
        /// The graphic control extension for this frame.
        /// </param>
        /// <param name="act">
        /// The active colour table for this frame.
        /// </param>
        /// <returns></returns>
        private static Bitmap GetBaseImage(GifFrame previousFrame,
                                           GifFrame previousFrameBut1,
                                           LogicalScreenDescriptor lsd,
                                           GraphicControlExtension gce,
                                           ColourTable act)
        {
            #region Get the disposal method of the previous frame read from the GIF stream
            DisposalMethod previousDisposalMethod;
            if (previousFrame == null)
            {
                previousDisposalMethod = DisposalMethod.NotSpecified;
            }
            else
            {
                previousDisposalMethod = previousFrame.GraphicControlExtension.DisposalMethod;
            }
            #endregion

            Bitmap baseImage;
            int    width  = lsd.LogicalScreenSize.Width;
            int    height = lsd.LogicalScreenSize.Height;

            #region paint baseImage
            switch (previousDisposalMethod)
            {
            case DisposalMethod.DoNotDispose:
                // pre-populate image with previous frame
                baseImage = new Bitmap(previousFrame.TheImage);
                break;

            case DisposalMethod.RestoreToBackgroundColour:
                // pre-populate image with background colour
                Color backgroundColour;
                if (lsd.BackgroundColourIndex == gce.TransparentColourIndex)
                {
                    backgroundColour = Color.Empty;
                }
                else
                {
                    // TESTME: background colour index different to transparent colour
                    backgroundColour = act[lsd.BackgroundColourIndex];
                }
                baseImage = new Bitmap(width, height);
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < height; x++)
                    {
                        baseImage.SetPixel(x, y, backgroundColour);
                    }
                }
                break;

            case DisposalMethod.RestoreToPrevious:
                // pre-populate image with previous frame but 1
                // TESTME: DisposalMethod.RestoreToPrevious
                baseImage = new Bitmap(previousFrameBut1.TheImage);
                break;

            default:                     // DisposalMethod.NotSpecified
                if (previousFrame == null)
                {
                    // this is the first frame so start with an empty bitmap
                    baseImage = new Bitmap(width, height);
                }
                else
                {
                    // pre-populate image with previous frame
                    // TESTME: DisposalMethod.NotSpecified on 2nd frame or later
                    baseImage = new Bitmap(previousFrame.TheImage);
                }
                break;
            }
            #endregion

            return(baseImage);
        }
Beispiel #3
0
        /// <summary>
        /// Sets the pixels of the decoded image.
        /// </summary>
        /// <param name="imageData">
        /// Table based image data containing the indices within the active
        /// colour table of the colours of the pixels in this frame.
        /// </param>
        /// <param name="lsd">
        /// The logical screen descriptor for the GIF stream.
        /// </param>
        /// <param name="id">
        /// The image descriptor for this frame.
        /// </param>
        /// <param name="activeColourTable">
        /// The colour table to use with this frame - either the global colour
        /// table or a local colour table.
        /// </param>
        /// <param name="gce">
        /// The graphic control extension, if any, which precedes this image in
        /// the input stream.
        /// </param>
        /// <param name="previousFrame">
        /// The frame which precedes this one in the GIF stream, if present.
        /// </param>
        /// <param name="previousFrameBut1">
        /// The frame which precedes the frame before this one in the GIF stream,
        /// if present.
        /// </param>
        /// <param name="status">
        /// GifComponentStatus containing any errors which occurred during the
        /// creation of the bitmap.
        /// </param>
        private static Bitmap CreateBitmap(TableBasedImageData imageData,
                                           LogicalScreenDescriptor lsd,
                                           ImageDescriptor id,
                                           ColourTable activeColourTable,
                                           GraphicControlExtension gce,
                                           GifFrame previousFrame,
                                           GifFrame previousFrameBut1,
                                           out GifComponentStatus status)
        {
            status = new GifComponentStatus(ErrorState.Ok, "");
            Color[] pixelsForThisFrame = new Color[lsd.LogicalScreenSize.Width
                                                   * lsd.LogicalScreenSize.Height];

            Bitmap baseImage = GetBaseImage(previousFrame,
                                            previousFrameBut1,
                                            lsd,
                                            gce,
                                            activeColourTable);

            // copy each source line to the appropriate place in the destination
            int pass = 1;
            int interlaceRowIncrement = 8;
            int interlaceRowNumber    = 0;          // the row of pixels we're currently

            // setting in an interlaced image.
            for (int i = 0; i < id.Size.Height; i++)
            {
                int pixelRowNumber = i;
                if (id.IsInterlaced)
                {
                    #region work out the pixel row we're setting for an interlaced image
                    if (interlaceRowNumber >= id.Size.Height)
                    {
                        pass++;
                        switch (pass)
                        {
                        case 2:
                            interlaceRowNumber = 4;
                            break;

                        case 3:
                            interlaceRowNumber    = 2;
                            interlaceRowIncrement = 4;
                            break;

                        case 4:
                            interlaceRowNumber    = 1;
                            interlaceRowIncrement = 2;
                            break;
                        }
                    }
                    #endregion
                    pixelRowNumber      = interlaceRowNumber;
                    interlaceRowNumber += interlaceRowIncrement;
                }

                // Colour in the pixels for this row
                pixelRowNumber += id.Position.Y;
                if (pixelRowNumber < lsd.LogicalScreenSize.Height)
                {
                    int k    = pixelRowNumber * lsd.LogicalScreenSize.Width;
                    int dx   = k + id.Position.X;                   // start of line in dest
                    int dlim = dx + id.Size.Width;                  // end of dest line
                    if ((k + lsd.LogicalScreenSize.Width) < dlim)
                    {
                        // TESTME: CreateBitmap - past dest edge
                        dlim = k + lsd.LogicalScreenSize.Width;     // past dest edge
                    }
                    int sx = i * id.Size.Width;                     // start of line in source
                    while (dx < dlim)
                    {
                        // map color and insert in destination
                        int indexInColourTable = (int)imageData.Pixels[sx++];
                        // Set this pixel's colour if its index isn't the
                        // transparent colour index, or if this frame doesn't
                        // have a transparent colour.
                        Color c;
                        if (gce.HasTransparentColour && indexInColourTable == gce.TransparentColourIndex)
                        {
                            c = Color.Empty;                             // transparent pixel
                        }
                        else
                        {
                            if (indexInColourTable < activeColourTable.Length)
                            {
                                c = activeColourTable[indexInColourTable];
                            }
                            else
                            {
                                // TESTME: CreateBitmap - BadColourIndex
                                c = Color.Black;
                                string message
                                    = "Colour index: "
                                      + indexInColourTable
                                      + ", colour table length: "
                                      + activeColourTable.Length
                                      + " (" + dx + "," + pixelRowNumber + ")";
                                status = new GifComponentStatus(ErrorState.BadColourIndex,
                                                                message);
                            }
                        }
                        pixelsForThisFrame[dx] = c;
                        dx++;
                    }
                }
            }
            return(CreateBitmap(baseImage, pixelsForThisFrame));
        }
Beispiel #4
0
        public GifFrame(Stream inputStream,
                        LogicalScreenDescriptor lsd,
                        ColourTable gct,
                        GraphicControlExtension gce,
                        GifFrame previousFrame,
                        GifFrame previousFrameBut1,
                        bool xmlDebugging)
            : base(xmlDebugging)
        {
            #region guard against null arguments
            if (lsd == null)
            {
                throw new ArgumentNullException("lsd");
            }

            if (gce == null)
            {
                SetStatus(ErrorState.NoGraphicControlExtension, "");
                // use a default GCE
                gce = new GraphicControlExtension(GraphicControlExtension.ExpectedBlockSize,
                                                  DisposalMethod.NotSpecified,
                                                  false,
                                                  false,
                                                  100,
                                                  0);
            }
            #endregion

            int transparentColourIndex = gce.TransparentColourIndex;

            ImageDescriptor imageDescriptor = new ImageDescriptor(inputStream,
                                                                  XmlDebugging);
            WriteDebugXmlNode(imageDescriptor.DebugXmlReader);

            #region determine the colour table to use for this frame
            Color backgroundColour = Color.FromArgb(0);               // TODO: is this the right background colour?
            // TODO: use backgroundColourIndex from the logical screen descriptor?
            ColourTable activeColourTable;
            if (imageDescriptor.HasLocalColourTable)
            {
                _localColourTable
                    = new ColourTable(inputStream,
                                      imageDescriptor.LocalColourTableSize,
                                      XmlDebugging);
                WriteDebugXmlNode(_localColourTable.DebugXmlReader);
                activeColourTable = _localColourTable;                 // make local table active
            }
            else
            {
                if (gct == null)
                {
                    // We have neither local nor global colour table, so we
                    // won't be able to decode this frame.
                    Bitmap emptyBitmap = new Bitmap(lsd.LogicalScreenSize.Width,
                                                    lsd.LogicalScreenSize.Height);
                    _image = emptyBitmap;
                    _delay = gce.DelayTime;
                    SetStatus(ErrorState.FrameHasNoColourTable, "");
                    return;
                }
                activeColourTable = gct;                 // make global table active
                if (lsd.BackgroundColourIndex == transparentColourIndex)
                {
                    backgroundColour = Color.FromArgb(0);
                }
            }
            #endregion

            // decode pixel data
            int pixelCount = imageDescriptor.Size.Width * imageDescriptor.Size.Height;
            TableBasedImageData indexedPixels
                = new TableBasedImageData(inputStream, pixelCount, XmlDebugging);
            WriteDebugXmlNode(indexedPixels.DebugXmlReader);

            if (indexedPixels.Pixels.Count == 0)
            {
                // TESTME: constructor - indexedPixels.Pixels.Count == 0
                Bitmap emptyBitmap = new Bitmap(lsd.LogicalScreenSize.Width,
                                                lsd.LogicalScreenSize.Height);
                _image = emptyBitmap;
                _delay = gce.DelayTime;
                SetStatus(ErrorState.FrameHasNoImageData, "");
                WriteDebugXmlFinish();
                return;
            }

            // Skip any remaining blocks up to the next block terminator (in
            // case there is any surplus data before the next frame)
            SkipBlocks(inputStream);

            _indexedPixels = indexedPixels;

            _extension = gce;
            if (gce != null)
            {
                _delay = gce.DelayTime;
            }
            _imageDescriptor  = imageDescriptor;
            _backgroundColour = backgroundColour;
            GifComponentStatus status;
            _image = CreateBitmap(indexedPixels,
                                  lsd,
                                  imageDescriptor,
                                  activeColourTable,
                                  gce,
                                  previousFrame,
                                  previousFrameBut1,
                                  out status);

            WriteDebugXmlFinish();
        }