public void BlockTerminatorTest() { ReportStart(); byte[] bytes = new byte[] { 0x08, // LZW minimum code size 0x05, // block size = 5 // 5 bytes of LZW encoded data follows 0x00, 0x51, 0xFC, 0x1B, 0x28, 0x06, // block size = 6 // 6 bytes of LZW encoded data follows 0x70, 0xA0, 0xC1, 0x83, 0x01, 0x01, 0x00, // block terminator - end of table based image data }; MemoryStream s = new MemoryStream(); s.Write( bytes, 0, bytes.Length ); s.Seek( 0, SeekOrigin.Begin ); int pixelCount = WikipediaExample.FrameSize.Width * WikipediaExample.FrameSize.Height; _tbid = new TableBasedImageData( s, pixelCount ); Assert.AreEqual( ErrorState.Ok, _tbid.ConsolidatedState ); Assert.AreEqual( 15, _tbid.Pixels.Count ); Assert.AreEqual( ErrorState.Ok, _tbid.ConsolidatedState ); Assert.AreEqual( 8, _tbid.LzwMinimumCodeSize ); Assert.AreEqual( 9, _tbid.InitialCodeSize ); Assert.AreEqual( Math.Pow( 2, 8 ), _tbid.ClearCode ); Assert.AreEqual( Math.Pow( 2, 8 ) + 1, _tbid.EndOfInformation ); IndexedPixels expectedIndices = new IndexedPixels(); expectedIndices.Add( 40 ); // first pixel is black - index 0 in colour table expectedIndices.Add( 255 ); // 2nd pixel is white - index 255 in colour table expectedIndices.Add( 255 ); // 3rd pixel expectedIndices.Add( 255 ); // 4th pixel expectedIndices.Add( 40 ); // 5th pixel expectedIndices.Add( 255 ); // 6th pixel expectedIndices.Add( 255 ); // 7th pixel expectedIndices.Add( 255 ); // 8th pixel expectedIndices.Add( 255 ); // 9th pixel expectedIndices.Add( 255 ); // 10th pixel expectedIndices.Add( 255 ); // 11th pixel expectedIndices.Add( 255 ); // 12th pixel expectedIndices.Add( 255 ); // 13th pixel expectedIndices.Add( 255 ); // 14th pixel expectedIndices.Add( 255 ); // 15th pixel for( int i = 0; i < 15; i++ ) { Assert.AreEqual( expectedIndices[i], _tbid.Pixels[i], "pixel " + i ); } ReportEnd(); }
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(); }
private void MinimumCodeSizeTooLarge( bool xmlDebugging ) { byte[] bytes = new byte[] { 12, // LZW minimum code size }; MemoryStream s = new MemoryStream(); s.Write( bytes, 0, bytes.Length ); s.Seek( 0, SeekOrigin.Begin ); _tbid = new TableBasedImageData( s, 25, xmlDebugging ); // Processing will be abandoned before any pixels are set Assert.AreEqual( ErrorState.LzwMinimumCodeSizeTooLarge, _tbid.ConsolidatedState ); // TBID will still return the number of pixels passed to the constructor Assert.AreEqual( 25, _tbid.Pixels.Count ); Assert.AreEqual( 12, _tbid.LzwMinimumCodeSize ); Assert.AreEqual( 13, _tbid.InitialCodeSize ); Assert.AreEqual( Math.Pow( 2, 12 ), _tbid.ClearCode ); Assert.AreEqual( Math.Pow( 2, 12 ) + 1, _tbid.EndOfInformation ); if( xmlDebugging ) { Assert.AreEqual( ExpectedDebugXml, _tbid.DebugXml ); } }
private void MissingPixels( bool xmlDebugging ) { byte[] bytes = WikipediaExample.ImageDataBytes; MemoryStream s = new MemoryStream(); s.Write( bytes, 0, bytes.Length ); s.Seek( 0, SeekOrigin.Begin ); // The stream contains 15 pixels, this image size implies 18 pixels _tbid = new TableBasedImageData( s, 18, xmlDebugging ); Assert.AreEqual( 18, _tbid.Pixels.Count ); Assert.AreEqual( ErrorState.TooFewPixelsInImageData, _tbid.ConsolidatedState ); Assert.AreEqual( 8, _tbid.LzwMinimumCodeSize ); Assert.AreEqual( 9, _tbid.InitialCodeSize ); Assert.AreEqual( Math.Pow( 2, 8 ), _tbid.ClearCode ); Assert.AreEqual( Math.Pow( 2, 8 ) + 1, _tbid.EndOfInformation ); IndexedPixels expectedIndices = new IndexedPixels(); expectedIndices.Add( 0 ); // first pixel is black - index 0 in colour table expectedIndices.Add( 1 ); // 2nd pixel is white - index 1 in colour table expectedIndices.Add( 1 ); // 3rd pixel expectedIndices.Add( 1 ); // 4th pixel expectedIndices.Add( 0 ); // 5th pixel expectedIndices.Add( 1 ); // 6th pixel expectedIndices.Add( 1 ); // 7th pixel expectedIndices.Add( 1 ); // 8th pixel expectedIndices.Add( 1 ); // 9th pixel expectedIndices.Add( 1 ); // 10th pixel expectedIndices.Add( 1 ); // 11th pixel expectedIndices.Add( 1 ); // 12th pixel expectedIndices.Add( 1 ); // 13th pixel expectedIndices.Add( 1 ); // 14th pixel expectedIndices.Add( 1 ); // 15th pixel expectedIndices.Add( 0 ); // 16th pixel expectedIndices.Add( 0 ); // 17th pixel expectedIndices.Add( 0 ); // 18th pixel for( int i = 0; i < 18; i++ ) { Assert.AreEqual( expectedIndices[i], _tbid.Pixels[i], "pixel " + i ); } }
private void DataBlockTooShort( bool xmlDebugging ) { byte[] bytes = new byte[] { 0x08, // LZW minimum code size 0x0b, // block size = 11 // 11 bytes of LZW encoded data follows (actually there's only 10 for this test) 0x00, 0x51, 0xFC, 0x1B, 0x28, 0x70, 0xA0, 0xC1, 0x83, 0x01, //0x01, // 0x00 // block terminator }; MemoryStream s = new MemoryStream(); s.Write( bytes, 0, bytes.Length ); s.Seek( 0, SeekOrigin.Begin ); int pixelCount = WikipediaExample.FrameSize.Width * WikipediaExample.FrameSize.Height; _tbid = new TableBasedImageData( s, pixelCount, xmlDebugging ); Assert.AreEqual( 15, _tbid.Pixels.Count ); Assert.AreEqual( ErrorState.DataBlockTooShort | ErrorState.TooFewPixelsInImageData, _tbid.ConsolidatedState ); Assert.AreEqual( 8, _tbid.LzwMinimumCodeSize ); Assert.AreEqual( 9, _tbid.InitialCodeSize ); Assert.AreEqual( Math.Pow( 2, 8 ), _tbid.ClearCode ); Assert.AreEqual( Math.Pow( 2, 8 ) + 1, _tbid.EndOfInformation ); IndexedPixels expectedIndices = new IndexedPixels(); expectedIndices.Add( 0 ); // first pixel expectedIndices.Add( 0 ); // 2nd pixel expectedIndices.Add( 0 ); // 3rd pixel expectedIndices.Add( 0 ); // 4th pixel expectedIndices.Add( 0 ); // 5th pixel expectedIndices.Add( 0 ); // 6th pixel expectedIndices.Add( 0 ); // 7th pixel expectedIndices.Add( 0 ); // 8th pixel expectedIndices.Add( 0 ); // 9th pixel expectedIndices.Add( 0 ); // 10th pixel expectedIndices.Add( 0 ); // 11th pixel expectedIndices.Add( 0 ); // 12th pixel expectedIndices.Add( 0 ); // 13th pixel expectedIndices.Add( 0 ); // 14th pixel expectedIndices.Add( 0 ); // 15th pixel for( int i = 0; i < 15; i++ ) { Assert.AreEqual( expectedIndices[i], _tbid.Pixels[i], "pixel " + i ); } if( xmlDebugging ) { Assert.AreEqual( ExpectedDebugXml, _tbid.DebugXml ); } }
private void EmptyDataBlock( bool xmlDebugging ) { MemoryStream s = new MemoryStream(); s.WriteByte( 8 ); // write a valid LZW min code size s.WriteByte( 0 ); s.WriteByte( 0 ); s.Seek( 0, SeekOrigin.Begin ); _tbid = new TableBasedImageData( s, 100, xmlDebugging ); Assert.AreEqual( ErrorState.TooFewPixelsInImageData, _tbid.ConsolidatedState ); if( xmlDebugging ) { Assert.AreEqual( ExpectedDebugXml, _tbid.DebugXml ); } }
private void CodeNotInDictionary( bool xmlDebugging ) { byte[] bytes = WikipediaExample.ImageDataBytes; bytes[4] = 0xFF; // put an unexpected code into the stream MemoryStream s = new MemoryStream(); s.Write( bytes, 0, bytes.Length ); s.Seek( 0, SeekOrigin.Begin ); int pixelCount = WikipediaExample.FrameSize.Width * WikipediaExample.FrameSize.Height; _tbid = new TableBasedImageData( s, pixelCount, xmlDebugging ); Assert.IsTrue( _tbid.TestState( ErrorState.CodeNotInDictionary ) ); Assert.AreEqual( 15, _tbid.Pixels.Count ); Assert.AreEqual( 8, _tbid.LzwMinimumCodeSize ); Assert.AreEqual( 9, _tbid.InitialCodeSize ); Assert.AreEqual( Math.Pow( 2, 8 ), _tbid.ClearCode ); Assert.AreEqual( Math.Pow( 2, 8 ) + 1, _tbid.EndOfInformation ); IndexedPixels expectedIndices = new IndexedPixels(); // Check all the pixels have been zero-filled expectedIndices.Add( 0 ); // first pixel expectedIndices.Add( 0 ); // 2nd pixel expectedIndices.Add( 0 ); // 3rd pixel expectedIndices.Add( 0 ); // 4th pixel expectedIndices.Add( 0 ); // 5th pixel expectedIndices.Add( 0 ); // 6th pixel expectedIndices.Add( 0 ); // 7th pixel expectedIndices.Add( 0 ); // 8th pixel expectedIndices.Add( 0 ); // 9th pixel expectedIndices.Add( 0 ); // 10th pixel expectedIndices.Add( 0 ); // 11th pixel expectedIndices.Add( 0 ); // 12th pixel expectedIndices.Add( 0 ); // 13th pixel expectedIndices.Add( 0 ); // 14th pixel expectedIndices.Add( 0 ); // 15th pixel for( int i = 0; i < 15; i++ ) { Assert.AreEqual( expectedIndices[i], _tbid.Pixels[i], "pixel " + i ); } if( xmlDebugging ) { Assert.AreEqual( ExpectedDebugXml, _tbid.DebugXml ); } }
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 HandleRubbish() { ReportStart(); string[] files = Directory.GetFiles( Directory.GetCurrentDirectory() ); foreach( string file in files ) { byte[] bytes = File.ReadAllBytes( file ); MemoryStream s = new MemoryStream(); s.WriteByte( 8 ); // write a valid LZW min code size s.Write( bytes, 0, bytes.Length ); s.Seek( 0, SeekOrigin.Begin ); try { _tbid = new TableBasedImageData( s, 1000000 ); } catch( Exception ex ) { throw new InvalidOperationException( file + ": ", ex ); } } ReportEnd(); }
public void PixelCountTooSmall() { ReportStart(); int pixelCount = 0; try { _tbid = new TableBasedImageData( new MemoryStream(), pixelCount ); } catch( ArgumentOutOfRangeException ex ) { string message = "The pixel count must be greater than zero. " + "Supplied value was " + pixelCount; StringAssert.Contains( message, ex.Message ); Assert.AreEqual( "pixelCount", ex.ParamName ); ReportEnd(); throw; } }
private static void CheckImageData( Stream s, ColourTable act, ImageDescriptor id, Bitmap expectedBitmap) { // 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 = id.Size.Width * id.Size.Height; TableBasedImageData tbid = new TableBasedImageData( s, pixelCount ); Assert.AreEqual( ErrorState.Ok, tbid.ConsolidatedState ); for( int y = 0; y < id.Size.Height; y++ ) { for( int x = 0; x < id.Size.Width; x++ ) { int i = (y * id.Size.Width) + x; Assert.AreEqual( expectedBitmap.GetPixel( x, y ), act[tbid.Pixels[i]], "X: " + x + ", Y: " + y ); } } }
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(); }
/// <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)); }
/// <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 ConstructorTest( bool xmlDebugging ) { byte[] bytes = WikipediaExample.ImageDataBytes; MemoryStream s = new MemoryStream(); s.Write( bytes, 0, bytes.Length ); s.Seek( 0, SeekOrigin.Begin ); int pixelCount = WikipediaExample.FrameSize.Width * WikipediaExample.FrameSize.Height; _tbid = new TableBasedImageData( s, pixelCount, xmlDebugging ); Assert.AreEqual( ErrorState.Ok, _tbid.ConsolidatedState ); WikipediaExample.CheckImageData( _tbid ); if( xmlDebugging ) { Assert.AreEqual( ExpectedDebugXml, _tbid.DebugXml ); } }
internal static void CheckImageData( TableBasedImageData imageData ) { TableBasedImageData expectedData = ImageData; Assert.AreEqual( expectedData.ClearCode, imageData.ClearCode ); Assert.AreEqual( expectedData.DataBlocks.Length, imageData.DataBlocks.Length ); Assert.AreEqual( expectedData.EndOfInformation, imageData.EndOfInformation ); Assert.AreEqual( expectedData.InitialCodeSize, imageData.InitialCodeSize ); Assert.AreEqual( expectedData.LzwMinimumCodeSize, imageData.LzwMinimumCodeSize ); Assert.AreEqual( expectedData.Pixels.Count, imageData.Pixels.Count ); string info; for( int i = 0; i < expectedData.Pixels.Count; i++ ) { info = "Pixel index: " + i; Assert.AreEqual( expectedData.Pixels[i], imageData.Pixels[i], info ); } for( int i = 0; i < expectedData.DataBlocks.Length; i++ ) { info = "Data block number: " + i; DataBlock expectedBlock = expectedData.DataBlocks[i]; DataBlock actualBlock = imageData.DataBlocks[i]; Assert.AreEqual( expectedBlock.ActualBlockSize, actualBlock.ActualBlockSize, info ); Assert.AreEqual( expectedBlock.DeclaredBlockSize, actualBlock.DeclaredBlockSize, info ); for( int b = 0; b < expectedBlock.ActualBlockSize; b++ ) { Assert.AreEqual( expectedBlock.Data[i], actualBlock.Data[i], info + ". Block index " + b ); } } }
/// <summary> /// Encodes _ip and decodes the encoded data, then compares the decoded /// data against the original. /// Also calculates the compression rate. /// </summary> private void TestIt() { MemoryStream s = new MemoryStream(); _e = new LzwEncoder( _ip ); _e.Encode( s ); int encodedByteCount = (int) s.Position; s.Seek( 0, SeekOrigin.Begin ); TableBasedImageData tbid = new TableBasedImageData( s, _ip.Count ); s.Seek( 0, SeekOrigin.Begin ); byte[] encodedBytes = new byte[encodedByteCount]; s.Read( encodedBytes, 0, encodedByteCount ); Assert.AreEqual( _ip.Count, tbid.Pixels.Count, "Pixel counts differ" ); for( int i = 0; i < _ip.Count; i++ ) { Assert.AreEqual( _ip[i], tbid.Pixels[i], "pixel index " + i ); } float compression = 100 - (100 * encodedByteCount / _ip.Count); WriteMessage( "Original byte count: " + _ip.Count + ". Encoded byte count: " + encodedByteCount + ". Compression rate: " + compression + "%" ); }