/// <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; }
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(); }
/// <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 ); } }
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 ); }