예제 #1
0
		public GifFrame( Stream inputStream,
		                 LogicalScreenDescriptor lsd,
		                 ColourTable gct,
		                 GraphicControlExtension gce,
		                 GifFrame previousFrame,
		                 GifFrame previousFrameBut1 )
			: base( inputStream, lsd, gct, gce, previousFrame, previousFrameBut1 )
		{}
예제 #2
0
 public GifFrame(Stream inputStream,
                 LogicalScreenDescriptor lsd,
                 ColourTable gct,
                 GraphicControlExtension gce,
                 GifFrame previousFrame,
                 GifFrame previousFrameBut1)
     : this(inputStream, lsd, gct, gce, previousFrame, previousFrameBut1, false)
 {
 }
예제 #3
0
        /// <summary>
        /// Reads GIF image from stream
        /// </summary>
        /// <param name="inputStream">
        /// Stream containing GIF file.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// The supplied stream is null.
        /// </exception>
        private void ReadStream( Stream inputStream )
        {
            _frames = new Collection<GifFrame>();
            _applicationExtensions = new Collection<ApplicationExtension>();
            _gct = null;

            _readStreamCounterText = "Reading stream byte";
            AddCounter( _readStreamCounterText, (int) inputStream.Length );
            _header = new GifHeader( inputStream, XmlDebugging );
            MyProgressCounters[_readStreamCounterText].Value
                = (int) inputStream.Position;
            WriteDebugXmlNode( _header.DebugXmlReader );
            if( _header.ErrorState != ErrorState.Ok )
            {
                WriteDebugXmlFinish();
                return;
            }

            _lsd = new LogicalScreenDescriptor( inputStream, XmlDebugging );
            MyProgressCounters[_readStreamCounterText].Value
                = (int) inputStream.Position;
            WriteDebugXmlNode( _lsd.DebugXmlReader );
            if( TestState( ErrorState.EndOfInputStream ) )
            {
                WriteDebugXmlFinish();
                return;
            }

            if( _lsd.HasGlobalColourTable )
            {
                _gct = new ColourTable( inputStream,
                                        _lsd.GlobalColourTableSize,
                                        XmlDebugging );
                MyProgressCounters[_readStreamCounterText].Value
                    = (int) inputStream.Position;
                WriteDebugXmlNode( _gct.DebugXmlReader );
            }

            if( ConsolidatedState == ErrorState.Ok )
            {
                ReadContents( inputStream );
                MyProgressCounters[_readStreamCounterText].Value
                    = (int) inputStream.Position;
            }
            inputStream.Close();
            WriteDebugXmlFinish();
            RemoveCounter( _readStreamCounterText );
        }
        public void ConstructorTest()
        {
            ReportStart();

            int width = 15;
            int height = 20;
            Size screenSize = new Size( width, height );
            bool hasGlobalColourTable = true;
            int colourResolution = 6;
            bool colourTableIsSorted = false;
            int globalColourTableSizeBits = 3;
            int backgroundColourIndex = 12;
            int pixelAspectRatio = 2;

            _lsd = new LogicalScreenDescriptor( screenSize,
                                                hasGlobalColourTable,
                                                colourResolution,
                                                colourTableIsSorted,
                                                globalColourTableSizeBits,
                                                backgroundColourIndex,
                                                pixelAspectRatio );

            Assert.AreEqual( screenSize, _lsd.LogicalScreenSize );
            Assert.AreEqual( hasGlobalColourTable, _lsd.HasGlobalColourTable );
            Assert.AreEqual( colourResolution, _lsd.ColourResolution );
            Assert.AreEqual( colourTableIsSorted, _lsd.GlobalColourTableIsSorted );
            Assert.AreEqual( globalColourTableSizeBits,
                             _lsd.GlobalColourTableSizeBits );
            Assert.AreEqual( Math.Pow( 2, globalColourTableSizeBits + 1 ),
                             _lsd.GlobalColourTableSize );
            Assert.AreEqual( backgroundColourIndex, _lsd.BackgroundColourIndex );
            Assert.AreEqual( pixelAspectRatio, _lsd.PixelAspectRatio );
            Assert.AreEqual( ErrorState.Ok, _lsd.ConsolidatedState );

            ReportEnd();
        }
        private void ConstructorStreamTest( bool xmlDebugging )
        {
            int width = 15;
            int height = 20;
            Size screenSize = new Size( width, height );
            bool hasGlobalColourTable = true;
            int colourResolution = 6;
            bool colourTableIsSorted = false;
            int globalColourTableSizeBits = 3;
            int backgroundColourIndex = 12;
            int pixelAspectRatio = 2;

            MemoryStream s = new MemoryStream();

            // Write screen width and height, least significant bit first
            s.WriteByte( (byte) ( width & 0xff ) );
            s.WriteByte( (byte) ( ( width & 0xff00 ) >> 8 ) );
            s.WriteByte( (byte) ( height & 0xff ) );
            s.WriteByte( (byte) ( ( height & 0xff00 ) >> 8 ) );

            // Packed fields:
            //	bit 1 = global colour table flag
            //	bits 2-4 = colour resolution
            //	bit 5 = sort flag
            //	bits 6-8 = global colour table size
            byte packed = (byte)
                (
                      ( hasGlobalColourTable ? 1 : 0 ) << 7
                    | ( colourResolution & 7 ) << 4
                    | ( colourTableIsSorted ? 1 : 0 ) << 3
                    | ( globalColourTableSizeBits & 7 )
                );
            s.WriteByte( packed );

            s.WriteByte( (byte) backgroundColourIndex );
            s.WriteByte( (byte) pixelAspectRatio );

            s.Seek( 0, SeekOrigin.Begin );
            _lsd = new LogicalScreenDescriptor( s, xmlDebugging );

            Assert.AreEqual( ErrorState.Ok, _lsd.ConsolidatedState );
            Assert.AreEqual( screenSize, _lsd.LogicalScreenSize );
            Assert.AreEqual( hasGlobalColourTable, _lsd.HasGlobalColourTable );
            Assert.AreEqual( colourResolution, _lsd.ColourResolution );
            Assert.AreEqual( colourTableIsSorted, _lsd.GlobalColourTableIsSorted );
            Assert.AreEqual( globalColourTableSizeBits,
                             _lsd.GlobalColourTableSizeBits );
            Assert.AreEqual( Math.Pow( 2, globalColourTableSizeBits + 1 ),
                             _lsd.GlobalColourTableSize );
            Assert.AreEqual( backgroundColourIndex, _lsd.BackgroundColourIndex );
            Assert.AreEqual( pixelAspectRatio, _lsd.PixelAspectRatio );
            Assert.AreEqual( ErrorState.Ok, _lsd.ConsolidatedState );

            if( xmlDebugging )
            {
                Assert.AreEqual( ExpectedDebugXml, _lsd.DebugXml );
            }
        }
        private void ConstructorStreamEndOfStreamTest( bool xmlDebugging )
        {
            Size screenSize = new Size( 12, 4 );
            bool hasGlobalColourTable = false;
            int colourResolution = 3;
            bool globalColourTableIsSorted = true;
            int globalColourTableSizeBits = 4;
            int backgroundColourIndex = 2;
            int pixelAspectRatio = 1;
            _lsd = new LogicalScreenDescriptor( screenSize,
                                                hasGlobalColourTable,
                                                colourResolution,
                                                globalColourTableIsSorted,
                                                globalColourTableSizeBits,
                                                backgroundColourIndex,
                                                pixelAspectRatio );

            MemoryStream s = new MemoryStream();
            _lsd.WriteToStream( s );
            s.SetLength( s.Length - 1 ); // remove final byte from stream
            s.Seek( 0, SeekOrigin.Begin );
            _lsd = new LogicalScreenDescriptor( s, xmlDebugging );

            Assert.AreEqual( ErrorState.EndOfInputStream, _lsd.ConsolidatedState );
            Assert.AreEqual( screenSize, _lsd.LogicalScreenSize );
            Assert.AreEqual( hasGlobalColourTable, _lsd.HasGlobalColourTable );
            Assert.AreEqual( colourResolution, _lsd.ColourResolution );
            Assert.AreEqual( globalColourTableIsSorted, _lsd.GlobalColourTableIsSorted );
            Assert.AreEqual( globalColourTableSizeBits, _lsd.GlobalColourTableSizeBits );
            Assert.AreEqual( backgroundColourIndex, _lsd.BackgroundColourIndex );
            Assert.AreEqual( -1, _lsd.PixelAspectRatio );

            if( xmlDebugging )
            {
                Assert.AreEqual( ExpectedDebugXml, _lsd.DebugXml );
            }
        }
        private void DecodeSmiley( bool xmlDebugging )
        {
            string fileName = @"images\smiley\smiley.gif";
            _decoder = new GifDecoder( fileName, xmlDebugging );
            _decoder.Decode();
            _lsd = _decoder.LogicalScreenDescriptor;
            int expectedColourTableSize = 128;

            Assert.AreEqual( "GIF", _decoder.Header.Signature );
            Assert.AreEqual( "89a", _decoder.Header.Version );
            Assert.IsNotNull( _decoder.GlobalColourTable );
            Assert.AreEqual( true, _lsd.HasGlobalColourTable );
            Assert.AreEqual( expectedColourTableSize,
                             _lsd.GlobalColourTableSize );
            Assert.AreEqual( expectedColourTableSize,
                                _decoder.GlobalColourTable.Length );
            Assert.AreEqual( 7, _lsd.ColourResolution );
            Assert.AreEqual( Color.FromArgb( 255, 0, 0, 255 ), _decoder.BackgroundColour );
            Assert.AreEqual( 0, _lsd.BackgroundColourIndex );
            Assert.AreEqual( false, _lsd.GlobalColourTableIsSorted );
            Assert.AreEqual( 18, _lsd.LogicalScreenSize.Width );
            Assert.AreEqual( 18, _lsd.LogicalScreenSize.Height );
            Assert.AreEqual( 0, _lsd.PixelAspectRatio );
            Assert.AreEqual( 0, _decoder.NetscapeExtension.LoopCount );
            Assert.AreEqual( ErrorState.Ok, _decoder.ConsolidatedState );
            Assert.AreEqual( 4, _decoder.Frames.Count );
            int frameNumber = 0;
            string frameId;
            foreach( GifFrame thisFrame in _decoder.Frames )
            {
                frameId = "Frame " + frameNumber;
                Assert.IsNull( thisFrame.LocalColourTable, frameId );

                #region image descriptor properties
                ImageDescriptor descriptor = thisFrame.ImageDescriptor;
                Assert.AreEqual( false, descriptor.HasLocalColourTable, frameId );
                Assert.AreEqual( expectedColourTableSize,
                                 descriptor.LocalColourTableSize,
                                 frameId );
                Assert.AreEqual( false, descriptor.IsInterlaced, frameId );
                Assert.AreEqual( false, descriptor.IsSorted, frameId );
                #endregion

                #region graphic control extension properties
                GraphicControlExtension gce = thisFrame.GraphicControlExtension;
                Assert.AreEqual( 4, gce.BlockSize, frameId );
                Assert.AreEqual( 0, gce.TransparentColourIndex, frameId );
                Assert.IsTrue( gce.HasTransparentColour, frameId );
                Assert.IsFalse( gce.ExpectsUserInput, frameId );
                #endregion

                switch( frameNumber )
                {
                    case 0:
                        Assert.AreEqual( 250, thisFrame.Delay, frameId );
                        Assert.AreEqual( 250, gce.DelayTime, frameId );
                        Assert.AreEqual( DisposalMethod.DoNotDispose,
                                         gce.DisposalMethod, frameId );
                        break;
                    case 1:
                        Assert.AreEqual( 5, thisFrame.Delay, frameId );
                        Assert.AreEqual( 5, gce.DelayTime, frameId );
                        Assert.AreEqual( DisposalMethod.RestoreToBackgroundColour,
                                         gce.DisposalMethod, frameId );
                        break;
                    case 2:
                        Assert.AreEqual( 10, thisFrame.Delay, frameId );
                        Assert.AreEqual( 10, gce.DelayTime, frameId );
                        Assert.AreEqual( DisposalMethod.RestoreToBackgroundColour,
                                         gce.DisposalMethod, frameId );
                        break;
                    case 3:
                        Assert.AreEqual( 5, thisFrame.Delay, frameId );
                        Assert.AreEqual( 5, gce.DelayTime, frameId );
                        Assert.AreEqual( DisposalMethod.DoNotDispose,
                                         gce.DisposalMethod, frameId );
                        break;
                }
                frameNumber++;
            }
            CompareFrames( fileName );

            if( xmlDebugging )
            {
                Assert.AreEqual( ExpectedDebugXml, _decoder.DebugXml );
            }
        }
예제 #8
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;
		}
 private static LogicalScreenDescriptor CheckLogicalScreenDescriptor( Stream s,
     bool shouldHaveGlobalColourTable)
 {
     // check logical screen descriptor
     LogicalScreenDescriptor lsd = new LogicalScreenDescriptor( s );
     Assert.AreEqual( ErrorState.Ok,
                      lsd.ConsolidatedState,
                      "Logical screen descriptor consolidated state" );
     Assert.AreEqual( new Size( 2, 2 ),
                      lsd.LogicalScreenSize,
                      "Logical screen size" );
     Assert.AreEqual( shouldHaveGlobalColourTable,
                      lsd.HasGlobalColourTable,
                      "Should have global colour table" );
     Assert.AreEqual( false,
                      lsd.GlobalColourTableIsSorted,
                      "Global colour table is sorted" );
     return lsd;
 }
        public void WikipediaExampleTest()
        {
            ReportStart();
            _e = new AnimatedGifEncoder();
            GifFrame frame = new GifFrame( WikipediaExample.ExpectedBitmap );
            frame.Delay = WikipediaExample.DelayTime;
            _e.AddFrame( frame );

            // TODO: some way of creating/testing a UseLocal version of WikipediaExample
            string fileName = "WikipediaExampleUseGlobal.gif";
            _e.WriteToFile( fileName );
            Stream s = File.OpenRead( fileName );

            int code;

            // check GIF header
            GifHeader gh = new GifHeader( s );
            Assert.AreEqual( ErrorState.Ok, gh.ConsolidatedState );

            // check logical screen descriptor
            LogicalScreenDescriptor lsd = new LogicalScreenDescriptor( s );
            Assert.AreEqual( ErrorState.Ok, lsd.ConsolidatedState );
            WikipediaExample.CheckLogicalScreenDescriptor( lsd );

            // read global colour table
            ColourTable gct
                = new ColourTable( s, WikipediaExample.GlobalColourTableSize );
            Assert.AreEqual( ErrorState.Ok, gct.ConsolidatedState );
            // cannot compare global colour table as different encoders will
            // produce difference colour tables.
            //			WikipediaExample.CheckGlobalColourTable( gct );

            // check for extension introducer
            code = ExampleComponent.CallRead( s );
            Assert.AreEqual( GifComponent.CodeExtensionIntroducer, code );

            // check for app extension label
            code = ExampleComponent.CallRead( s );
            Assert.AreEqual( GifComponent.CodeApplicationExtensionLabel, code );

            // check netscape extension
            ApplicationExtension ae = new ApplicationExtension( s );
            Assert.AreEqual( ErrorState.Ok, ae.ConsolidatedState );
            NetscapeExtension ne = new NetscapeExtension( ae );
            Assert.AreEqual( ErrorState.Ok, ne.ConsolidatedState );
            Assert.AreEqual( 0, ne.LoopCount );

            // check for extension introducer
            code = ExampleComponent.CallRead( s );
            Assert.AreEqual( GifComponent.CodeExtensionIntroducer, code );

            // check for gce label
            code = ExampleComponent.CallRead( s );
            Assert.AreEqual( GifComponent.CodeGraphicControlLabel, code );

            // check graphic control extension
            GraphicControlExtension gce = new GraphicControlExtension( s );
            Assert.AreEqual( ErrorState.Ok, gce.ConsolidatedState );
            WikipediaExample.CheckGraphicControlExtension( gce );

            // check for image separator
            code = ExampleComponent.CallRead( s );
            Assert.AreEqual( GifComponent.CodeImageSeparator, code );

            // check for image descriptor
            ImageDescriptor id = new ImageDescriptor( s );
            Assert.AreEqual( ErrorState.Ok, id.ConsolidatedState );
            WikipediaExample.CheckImageDescriptor( id );

            // read, decode and check image data
            // Cannot compare encoded LZW data directly as different encoders
            // will create different colour tables, so even if the bitmaps are
            // identical, the colour indices will be different
            int pixelCount = WikipediaExample.FrameSize.Width
                            * WikipediaExample.FrameSize.Height;
            TableBasedImageData tbid = new TableBasedImageData( s, pixelCount );
            for( int y = 0; y < WikipediaExample.LogicalScreenSize.Height; y++ )
            {
                for( int x = 0; x < WikipediaExample.LogicalScreenSize.Width; x++ )
                {
                    int i = (y * WikipediaExample.LogicalScreenSize.Width) + x;
                    Assert.AreEqual( WikipediaExample.ExpectedBitmap.GetPixel( x, y ),
                                     gct[tbid.Pixels[i]],
                                     "X: " + x + ", Y: " + y );
                }
            }

            // Check for block terminator after image data
            code = ExampleComponent.CallRead( s );
            Assert.AreEqual( 0x00, code );

            // check for GIF trailer
            code = ExampleComponent.CallRead( s );
            Assert.AreEqual( GifComponent.CodeTrailer, code );

            // check we're at the end of the stream
            code = ExampleComponent.CallRead( s );
            Assert.AreEqual( -1, code );
            s.Close();

            _d = new GifDecoder( fileName );
            _d.Decode();
            Assert.AreEqual( ErrorState.Ok, _d.ConsolidatedState );
            BitmapAssert.AreEqual( WikipediaExample.ExpectedBitmap,
                                  (Bitmap) _d.Frames[0].TheImage,
                                   "" );
            ReportEnd();
        }
예제 #11
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);
        }
예제 #12
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));
        }
예제 #13
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();
        }
예제 #14
0
		/// <summary>
		/// Writes a Logical Screen Descriptor to the supplied stream.
		/// Also writes a global colour table if required.
		/// </summary>
		/// <param name="outputStream">
		/// The stream to write to.
		/// </param>
		private void WriteLogicalScreenDescriptor( Stream outputStream )
		{
			bool hasGlobalColourTable = _strategy == ColourTableStrategy.UseGlobal;
			int colourResolution = 7; // TODO: parameterise colourResolution?
			bool globalColourTableIsSorted = false; // Sorting of colour tables is not currently supported
			int backgroundColorIndex = 0; // TODO: parameterise backgroundColourIndex?
			int pixelAspectRatio = 0; // TODO: parameterise pixelAspectRatio?
			if( _strategy == ColourTableStrategy.UseGlobal )
			{
				if( _quantizerType == QuantizerType.UseSuppliedPalette )
				{
					// use supplied palette
					_globalColourTable = new ColourTable();
					string buildColourTableCounterText 
						= "Building colour table from supplied palette";
					AddCounter( buildColourTableCounterText, 
					            _palette.Count );
					int paletteIndex = 0;
					foreach( Color c in _palette )
					{
						_globalColourTable.Add( c );
						MyProgressCounters[buildColourTableCounterText].Value 
							= paletteIndex;
						paletteIndex++;
					}
					_globalColourTable.Pad();
					RemoveCounter( buildColourTableCounterText );
				}
				else
				{
					// Analyse the pixels in all the images to build the
					// global colour table.
					Collection<Image> images = new Collection<Image>();
					foreach( GifFrame thisFrame in _frames )
					{
						Image thisImage = thisFrame.TheImage;
						images.Add( thisImage );
					}
					_pixelAnalysis = new PixelAnalysis( images );
					_pixelAnalysis.ColourQuality = _quality;
					_pixelAnalysis.Analyse();
					_globalColourTable = _pixelAnalysis.ColourTable;
				}
				LogicalScreenDescriptor lsd = 
					new LogicalScreenDescriptor( _logicalScreenSize, 
					                             hasGlobalColourTable, 
					                             colourResolution, 
					                             globalColourTableIsSorted, 
					                             _globalColourTable.SizeBits,
					                             backgroundColorIndex, 
					                             pixelAspectRatio );
				lsd.WriteToStream( outputStream );
				_globalColourTable.WriteToStream( outputStream );
			}
			else
			{
				LogicalScreenDescriptor lsd = 
					new LogicalScreenDescriptor( _logicalScreenSize, 
					                             hasGlobalColourTable, 
					                             colourResolution, 
					                             globalColourTableIsSorted, 
					                             7, 
					                             backgroundColorIndex, 
					                             pixelAspectRatio );
				lsd.WriteToStream( outputStream );
			}
		}
예제 #15
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();
		}
        public void ConstructorTestTooWide()
        {
            ReportStart();

            int width = ushort.MaxValue + 1;
            int height = 20;
            Size screenSize = new Size( width, height );
            bool hasGlobalColourTable = true;
            int colourResolution = 6;
            bool colourTableIsSorted = false;
            int globalColourTableSizeBits = 3;
            int backgroundColourIndex = 12;
            int pixelAspectRatio = 2;

            try
            {
                _lsd = new LogicalScreenDescriptor( screenSize,
                                                    hasGlobalColourTable,
                                                    colourResolution,
                                                    colourTableIsSorted,
                                                    globalColourTableSizeBits,
                                                    backgroundColourIndex,
                                                    pixelAspectRatio );
            }
            catch( ArgumentException ex )
            {
                string message
                    = "Logical screen width cannot be more than "
                    + ushort.MaxValue + ". "
                    + "Supplied value: " + width;
                StringAssert.Contains( message, ex.Message );
                Assert.AreEqual( "logicalScreenSize", ex.ParamName );
                ReportEnd();
                throw;
            }
        }
예제 #17
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 );
		}
        public void WriteToStreamTest()
        {
            ReportStart();

            Size screenSize = new Size( 12, 4 );
            bool hasGlobalColourTable = false;
            int colourResolution = 3;
            bool globalColourTableIsSorted = true;
            int globalColourTableSizeBits = 4;
            int backgroundColourIndex = 2;
            int pixelAspectRatio = 1;
            _lsd = new LogicalScreenDescriptor( screenSize,
                                                hasGlobalColourTable,
                                                colourResolution,
                                                globalColourTableIsSorted,
                                                globalColourTableSizeBits,
                                                backgroundColourIndex,
                                                pixelAspectRatio );

            MemoryStream s = new MemoryStream();
            _lsd.WriteToStream( s );
            s.Seek( 0, SeekOrigin.Begin );
            _lsd = new LogicalScreenDescriptor( s );

            Assert.AreEqual( ErrorState.Ok, _lsd.ConsolidatedState );
            Assert.AreEqual( screenSize, _lsd.LogicalScreenSize );
            Assert.AreEqual( hasGlobalColourTable, _lsd.HasGlobalColourTable );
            Assert.AreEqual( colourResolution, _lsd.ColourResolution );
            Assert.AreEqual( globalColourTableIsSorted, _lsd.GlobalColourTableIsSorted );
            Assert.AreEqual( globalColourTableSizeBits, _lsd.GlobalColourTableSizeBits );
            Assert.AreEqual( backgroundColourIndex, _lsd.BackgroundColourIndex );
            Assert.AreEqual( pixelAspectRatio, _lsd.PixelAspectRatio );

            ReportEnd();
        }
 /// <summary>
 /// Checks whether the supplied logical screen descriptor matches that
 /// returned by this class.
 /// </summary>
 /// <param name="lsd"></param>
 internal static void CheckLogicalScreenDescriptor( LogicalScreenDescriptor lsd )
 {
     Assert.AreEqual( BackgroundColourIndex,
                      lsd.BackgroundColourIndex,
                      "BackgroundColourIndex" );
     Assert.AreEqual( ColourResolution,
                      lsd.ColourResolution,
                      "ColourResolution" );
     Assert.AreEqual( GlobalColourTableSize,
                      lsd.GlobalColourTableSize,
                      "GlobalColourTableSize" );
     Assert.AreEqual( GlobalColourTableSizeBits,
                      lsd.GlobalColourTableSizeBits,
                      "GlobalColourTableSizeBits" );
     Assert.AreEqual( HasGlobalColourTable,
                      lsd.HasGlobalColourTable,
                      "HasGlobalColourTable" );
     Assert.AreEqual( LogicalScreenSize,
                      lsd.LogicalScreenSize,
                      "LogicalScreenSize" );
     Assert.AreEqual( PixelAspectRatio,
                      lsd.PixelAspectRatio,
                      "PixelAspectRatio" );
     Assert.AreEqual( GlobalColourTableIsSorted,
                      lsd.GlobalColourTableIsSorted,
                      "GlobalColourTableIsSorted" );
 }
        private void DecodeRotatingGlobe( bool xmlDebugging )
        {
            string fileName
                = @"images\globe\spinning globe better 200px transparent background.gif";
            _decoder = new GifDecoder( fileName, xmlDebugging );
            WriteMessage( "Started decoding. XmlDebugging=" + xmlDebugging );
            _decoder.Decode();
            WriteMessage( "Finished decoding. XmlDebugging=" + xmlDebugging );

            if( xmlDebugging )
            {
                Assert.AreEqual( ExpectedDebugXml, _decoder.DebugXml );
            }

            _lsd = _decoder.LogicalScreenDescriptor;
            int expectedColourTableSize = 64;

            Assert.AreEqual( ErrorState.Ok, _decoder.ConsolidatedState );
            Assert.AreEqual( "GIF", _decoder.Header.Signature );
            Assert.AreEqual( "89a", _decoder.Header.Version );
            Assert.IsNotNull( _decoder.GlobalColourTable );
            Assert.AreEqual( true, _lsd.HasGlobalColourTable );
            Assert.AreEqual( expectedColourTableSize,
                             _lsd.GlobalColourTableSize );
            Assert.AreEqual( expectedColourTableSize,
                                _decoder.GlobalColourTable.Length );
            Assert.AreEqual( 2, _lsd.ColourResolution );
            Assert.AreEqual( Color.FromArgb( 255, 255, 255, 255 ),
                             _decoder.BackgroundColour );
            Assert.AreEqual( 63, _lsd.BackgroundColourIndex );
            Assert.AreEqual( false, _lsd.GlobalColourTableIsSorted );
            Assert.AreEqual( 200, _lsd.LogicalScreenSize.Width );
            Assert.AreEqual( 191, _lsd.LogicalScreenSize.Height );
            Assert.AreEqual( 0, _lsd.PixelAspectRatio );
            Assert.AreEqual( 0, _decoder.NetscapeExtension.LoopCount );
            Assert.AreEqual( ErrorState.Ok, _decoder.ErrorState );
            Assert.AreEqual( 20, _decoder.Frames.Count );
            int frameNumber = 0;
            string frameId;
            foreach( GifFrame thisFrame in _decoder.Frames )
            {
                frameId = "Frame " + frameNumber;
                Assert.IsNull( thisFrame.LocalColourTable, frameId );
                Assert.AreEqual( 10, thisFrame.Delay, frameId );

                #region image descriptor tests
                ImageDescriptor descriptor = thisFrame.ImageDescriptor;
                Assert.AreEqual( false, descriptor.HasLocalColourTable, frameId );
                Assert.AreEqual( 2,
                                 descriptor.LocalColourTableSize,
                                 frameId );
                Assert.AreEqual( 200, descriptor.Size.Width, frameId );
                Assert.AreEqual( 191, descriptor.Size.Height, frameId );
                Assert.AreEqual( 0, descriptor.Position.X, frameId );
                Assert.AreEqual( 0, descriptor.Position.Y, frameId );
                Assert.AreEqual( false, descriptor.IsInterlaced, frameId );
                Assert.AreEqual( false, descriptor.IsSorted, frameId );
                #endregion

                #region graphic control extension tests
                GraphicControlExtension gce = thisFrame.GraphicControlExtension;
                Assert.AreEqual( 4, gce.BlockSize, frameId );
                Assert.AreEqual( 10, gce.DelayTime, frameId );
                if( frameNumber == 19 )
                {
                    Assert.AreEqual( DisposalMethod.DoNotDispose,
                                     gce.DisposalMethod, frameId );
                }
                else
                {
                    Assert.AreEqual( DisposalMethod.RestoreToBackgroundColour,
                                     gce.DisposalMethod, frameId );
                }
                Assert.AreEqual( 63, gce.TransparentColourIndex, frameId );
                Assert.IsTrue( gce.HasTransparentColour, frameId );
                Assert.IsFalse( gce.ExpectsUserInput, frameId );
                #endregion

                frameNumber++;
            }

            CompareFrames( fileName );
        }