Example #1
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;
		}
Example #2
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();
		}
Example #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 );
		}
        private void ConstructorStreamUseLocalTest( bool xmlDebugging )
        {
            _decoder = new GifDecoder( @"images\wikipedia example UseLocal.gif",
                                       xmlDebugging );
            _decoder.Decode();
            _frame = _decoder.Frames[0];

            Assert.AreEqual( ErrorState.Ok, _frame.ConsolidatedState );

            WikipediaExample.CheckImage( _frame.TheImage );

            // Check image descriptor
            ImageDescriptor id = _frame.ImageDescriptor;
            Assert.AreEqual( true, id.HasLocalColourTable,
                             "HasLocalColourTable" );
            Assert.AreEqual( false, id.IsInterlaced, "IsInterlaced" );
            Assert.AreEqual( false, id.IsSorted, "LocalColourTableIsSorted" );
            Assert.AreEqual( 4, id.LocalColourTableSize, "LocalColourTableSize" );
            Assert.AreEqual( new Point( 0, 0 ), id.Position, "Position" );
            Assert.AreEqual( new Size( 3, 5 ), id.Size, "Size" );

            WikipediaExample.CheckGraphicControlExtension( _frame.GraphicControlExtension );
            WikipediaExample.CheckImageData( _frame.IndexedPixels );
            Assert.AreEqual( 0, _frame.BackgroundColour.R );
            Assert.AreEqual( 0, _frame.BackgroundColour.G );
            Assert.AreEqual( 0, _frame.BackgroundColour.B );

            if( xmlDebugging )
            {
                Assert.AreEqual( ExpectedDebugXml, _frame.DebugXml );
            }
        }
Example #5
0
		public GifFrame( Stream inputStream,
		                 LogicalScreenDescriptor lsd,
		                 ColourTable gct,
		                 GraphicControlExtension gce,
		                 GifFrame previousFrame,
		                 GifFrame previousFrameBut1 )
			: this( inputStream, lsd, gct, gce, previousFrame, previousFrameBut1, false )
		{
			
		}
        private void ConstructorStreamNoImageDataTest( bool xmlDebugging )
        {
            MemoryStream s = new MemoryStream();

            // Image descriptor
            byte[] idBytes = WikipediaExample.ImageDescriptorBytes;
            s.Write( idBytes, 0, idBytes.Length );

            // miss out the image data
            //			// Table-based image data
            //			byte[] imageData = WikipediaExample.ImageDataBytes;
            //			s.Write( imageData, 0, imageData.Length );
            byte[] imageData = new byte[]
            {
                0x08, // LZW minimum code size
            //				0x00, // block size = 11
            //				// 11 bytes of LZW encoded data follows
            //				0x00, 0x01, 0x04, 0x18, 0x28, 0x70, 0xA0, 0xC1, 0x83, 0x01, 0x01,
                0x00 // block terminator
            };
            s.Write( imageData, 0, imageData.Length );

            s.Seek( 0, SeekOrigin.Begin );

            // Extra stuff not included in the frame stream, to pass to the
            // constructor
            ColourTable colourTable = WikipediaExample.GlobalColourTable;
            GraphicControlExtension ext = WikipediaExample.GraphicControlExtension;
            LogicalScreenDescriptor lsd = WikipediaExample.LogicalScreenDescriptor;

            _frame = new GifFrame( s, lsd, colourTable, ext, null, null, xmlDebugging );

            Assert.AreEqual( ErrorState.TooFewPixelsInImageData,
                             _frame.ConsolidatedState );

            if( xmlDebugging )
            {
                Assert.AreEqual( ExpectedDebugXml, _frame.DebugXml );
            }
        }
        private void ConstructorStreamTest( bool xmlDebugging )
        {
            MemoryStream s = CreateStream();

            // Extra stuff not included in the frame stream, to pass to the
            // constructor.
            ColourTable colourTable = WikipediaExample.GlobalColourTable;
            GraphicControlExtension ext = WikipediaExample.GraphicControlExtension;
            LogicalScreenDescriptor lsd = WikipediaExample.LogicalScreenDescriptor;

            _frame = new GifFrame( s, lsd, colourTable, ext, null, null, xmlDebugging );

            Assert.AreEqual( ErrorState.Ok, _frame.ConsolidatedState );

            WikipediaExample.CheckImage( _frame.TheImage );
            WikipediaExample.CheckImageDescriptor( _frame.ImageDescriptor );
            WikipediaExample.CheckGraphicControlExtension( _frame.GraphicControlExtension );
            WikipediaExample.CheckImageData( _frame.IndexedPixels );
            Assert.AreEqual( 0, _frame.BackgroundColour.R );
            Assert.AreEqual( 0, _frame.BackgroundColour.G );
            Assert.AreEqual( 0, _frame.BackgroundColour.B );

            if( xmlDebugging )
            {
                Assert.AreEqual( ExpectedDebugXml, _frame.DebugXml );
            }
        }
 public void Setup()
 {
     _frame = new GifFrame( WikipediaExample.ExpectedBitmap );
     Assert.AreEqual( 10, _frame.Delay );
     BitmapAssert.AreEqual( WikipediaExample.ExpectedBitmap,
                            (Bitmap) _frame.TheImage );
 }
        public void TransparencyTest()
        {
            ReportStart();
            Color noColour = Color.FromArgb( 0, 0, 0, 0 ); // note alpha of 0
            Color blue = Color.FromArgb( 0, 0, 255 );
            Color transparent = Color.FromArgb( 100, 100, 100 );
            _encoder = new AnimatedGifEncoder();
            _encoder.Transparent = transparent;

            // transparent | transparent
            // -------------------------
            // blue        | blue
            Bitmap bitmap = new Bitmap( 2, 2 );
            bitmap.SetPixel( 0, 0, transparent );
            bitmap.SetPixel( 1, 0, transparent );
            bitmap.SetPixel( 0, 1, blue );
            bitmap.SetPixel( 1, 1, blue );
            _frame = new GifFrame( bitmap );
            _encoder.AddFrame( _frame );

            // encode and decode
            string filename = "GifFrameTest.TransparencyTest.gif";
            _encoder.WriteToFile( filename );
            _decoder = new GifDecoder( filename );
            _decoder.Decode();
            Assert.AreEqual( ErrorState.Ok, _decoder.ConsolidatedState );

            // Result should be:
            // black | black
            // -------------
            // blue  | blue

            Bitmap actual = (Bitmap) _decoder.Frames[0].TheImage;
            Assert.AreEqual( noColour, actual.GetPixel( 0, 0 ) );
            Assert.AreEqual( noColour, actual.GetPixel( 1, 0 ) );
            Assert.AreEqual( blue, actual.GetPixel( 0, 1 ) );
            Assert.AreEqual( blue, actual.GetPixel( 1, 1 ) );

            ReportEnd();
        }
 public void PositionDecodedFrameGetTest()
 {
     ReportStart();
     _decoder = new GifDecoder( @"images\smiley\smiley.gif" );
     _decoder.Decode();
     for( int i = 0; i < _decoder.Frames.Count; i++ )
     {
         _frame = _decoder.Frames[i];
         Assert.AreEqual( _frame.ImageDescriptor.Position,
                          _frame.Position,
                          "Frame " + i );
     }
     ReportEnd();
 }
 public void PositionDecodedFrameSetTest()
 {
     ReportStart();
     _decoder = new GifDecoder( @"images\smiley\smiley.gif" );
     _decoder.Decode();
     _frame = _decoder.Frames[0];
     try
     {
         _frame.Position = new Point( 1, 1 );
     }
     catch( InvalidOperationException ex )
     {
         string message
             = "This GifFrame was returned by a GifDecoder so this "
             + "property is read-only";
         StringAssert.Contains( message, ex.Message );
         ReportEnd();
         throw;
     }
 }
 public void ExpectsUserInputDecodedFrameGetTest()
 {
     ReportStart();
     _decoder = new GifDecoder( @"images\smiley\smiley.gif" );
     _decoder.Decode();
     for( int i = 0; i < _decoder.Frames.Count; i++ )
     {
         _frame = _decoder.Frames[i];
         Assert.AreEqual( _frame.GraphicControlExtension.ExpectsUserInput,
                          _frame.ExpectsUserInput,
                          "Frame " + i );
     }
     ReportEnd();
 }
        public void ConstructorStreamNullLogicalScreenDescriptorTest()
        {
            MemoryStream s = CreateStream();

            // Extra stuff not included in the frame stream, to pass to the
            // constructor
            ColourTable colourTable = WikipediaExample.GlobalColourTable;
            GraphicControlExtension ext = WikipediaExample.GraphicControlExtension;
            LogicalScreenDescriptor lsd = null;

            try
            {
                _frame = new GifFrame( s, lsd, colourTable, ext, null, null );
            }
            catch( ArgumentNullException ex )
            {
                Assert.AreEqual( "lsd", ex.ParamName );
                throw;
            }
        }
        public void BadEncodingUsingGameboyPaletteLocal()
        {
            ReportStart();
            _e = new AnimatedGifEncoder();
            _e.ColourTableStrategy = ColourTableStrategy.UseLocal;
            _e.QuantizerType = QuantizerType.UseSuppliedPalette;

            GifFrame frame
                = new GifFrame( Image.FromFile( @"images\smiley.bmp" ) );
            _e.AddFrame( frame );

            Assert.AreEqual( ColourTableStrategy.UseLocal, _e.ColourTableStrategy );
            Assert.AreEqual( QuantizerType.UseSuppliedPalette, _e.QuantizerType );

            frame.Palette = Palette.FromFile( @"ColourTables\gameboy.act" );

            Assert.AreEqual( ColourTableStrategy.UseLocal, _e.ColourTableStrategy );
            Assert.AreEqual( QuantizerType.UseSuppliedPalette, _e.QuantizerType );

            _e.WriteToFile( GifFileName );

            _d = new GifDecoder( GifFileName );
            _d.Decode();

            Assert.AreEqual( ErrorState.Ok, _d.ConsolidatedState );

            ReportEnd();
        }
        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();
        }
        private void TestUseSuppliedPalette( ColourTableStrategy strategy )
        {
            string globalLocal
                = strategy == ColourTableStrategy.UseGlobal
                ? "Global"
                : "Local";
            // First, create and check a series of single-frame GIFs, one for
            // each of the available colour tables.
            string[] files = Directory.GetFiles( @"ColourTables", "*.act" );
            foreach( string act in files )
            {
                string actFileWithoutExtension
                    = Path.GetFileNameWithoutExtension( act );
                _e = new AnimatedGifEncoder();
                if( strategy == ColourTableStrategy.UseGlobal )
                {
                    _e.Palette = Palette.FromFile( act );
                    Assert.AreEqual( ColourTableStrategy.UseGlobal,
                                     _e.ColourTableStrategy );
                    // QuantizerType should default to UseSuppliedPalette when
                    // the encoder's Palette property is set.
                    Assert.AreEqual( QuantizerType.UseSuppliedPalette,
                                     _e.QuantizerType );
                }
                else
                {
                    _e.ColourTableStrategy = ColourTableStrategy.UseLocal;
                    Assert.AreEqual( ColourTableStrategy.UseLocal,
                                     _e.ColourTableStrategy );
                    _e.QuantizerType = QuantizerType.UseSuppliedPalette;
                    Assert.AreEqual( QuantizerType.UseSuppliedPalette,
                                     _e.QuantizerType );
                }

                GifFrame frame
                    = new GifFrame( Image.FromFile( @"images\smiley.bmp" ) );
                if( strategy == ColourTableStrategy.UseLocal )
                {
                    frame.Palette = Palette.FromFile( act );
                }
                _e.AddFrame( frame );

                string fileName
                    = "AnimatedGifEncoderTest.UseSuppliedPalette"
                    + globalLocal
                    + "-"
                    + actFileWithoutExtension
                    + ".gif";
                _e.WriteToFile( fileName );

                _d = new GifDecoder( fileName, true );
                _d.Decode();

                Assert.AreEqual( ErrorState.Ok, _d.ConsolidatedState,
                                 actFileWithoutExtension );
                Assert.AreEqual( 1, _d.Frames.Count, actFileWithoutExtension );

                if( strategy == ColourTableStrategy.UseGlobal )
                {
                    Assert.AreEqual( true,
                                     _d.LogicalScreenDescriptor.HasGlobalColourTable,
                                     actFileWithoutExtension );
                    Assert.IsNotNull( _d.GlobalColourTable,
                                      actFileWithoutExtension );
                }
                else
                {
                    Assert.AreEqual( false,
                                     _d.LogicalScreenDescriptor.HasGlobalColourTable,
                                     actFileWithoutExtension );
                    Assert.IsNull( _d.GlobalColourTable, actFileWithoutExtension );
                }

                string expectedFileName
                    = @"images\Smiley\Smiley"
                    + "-"
                    + actFileWithoutExtension
                    + ".bmp";
                Image expected = Image.FromFile( expectedFileName );
                ImageAssert.AreEqual( expected, _d.Frames[0].TheImage, expectedFileName );
            }

            // now encode a multi-frame animation with a user-supplied palette
            _d = new GifDecoder( @"images\globe\spinning globe better 200px transparent background.gif" );
            _d.Decode();
            _e = new AnimatedGifEncoder();
            _e.QuantizerType = QuantizerType.UseSuppliedPalette;
            _e.Palette = Palette.FromFile( @"ColourTables\C64.act" );
            foreach( GifFrame f in _d.Frames )
            {
                _e.AddFrame( f );
            }
            string globeFileName
                = "AnimatedGifEncoderTest.UseSuppliedPalette"
                + globalLocal
                + ".gif";
            _e.WriteToFile( globeFileName );

            _d = new GifDecoder( globeFileName );
            _d.Decode();
            Assert.AreEqual( ErrorState.Ok, _d.ConsolidatedState );
            Assert.AreEqual( _e.Frames.Count, _d.Frames.Count );
        }