static void Main(string[] args) { using (Stream stream = File.Open(@"d:\splash_loading.gif", FileMode.Open)) { GifParser parser = new GifParser(); parser.Initialize(stream); } }
public void LoadGif(string path) { Text = Caption + ": " + path; g = GifParser.Parse(path); UpdateList(); }
public void CreateGif() { parser = new GifParser(bytes); }
/// <summary> /// Decode byte array in multiple threads. /// </summary> public static void DecodeParallel(byte[] bytes, Action <DecodeProgress> onProgress) // TODO: Refact { if (_free) { throw new Exception("The Free version doesn't support this feature. Please consider buying the Full version of Power GIF."); } GifParser parser; try { parser = new GifParser(bytes); } catch (Exception e) { onProgress(new DecodeProgress { Exception = e, Completed = true }); return; } var decoded = new Dictionary <ImageDescriptor, byte[]>(); var frameCount = parser.Blocks.Count(i => i is ImageDescriptor); var decodeProgress = new DecodeProgress { FrameCount = frameCount }; for (var i = 0; i < parser.Blocks.Count; i++) { var imageDescriptor = parser.Blocks[i] as ImageDescriptor; if (imageDescriptor == null) { continue; } var data = (TableBasedImageData)parser.Blocks[i + 1 + imageDescriptor.LocalColorTableFlag]; ThreadPool.QueueUserWorkItem(context => { if (decodeProgress.Completed || decodeProgress.Exception != null) { return; } byte[] colorIndexes; try { colorIndexes = LzwDecoder.Decode(data.ImageData, data.LzwMinimumCodeSize); } catch (Exception e) { decodeProgress.Exception = e; decodeProgress.Completed = true; onProgress(decodeProgress); return; } lock (decoded) { decoded.Add(imageDescriptor, colorIndexes); decodeProgress.Progress++; if (decoded.Count == frameCount) { try { decodeProgress.Gif = CompleteDecode(parser, decoded); decodeProgress.Completed = true; } catch (Exception e) { decodeProgress.Exception = e; decodeProgress.Completed = true; } } onProgress(decodeProgress); } }); } }
/// <summary> /// Get frame count. Can be used with DecodeIterator to display progress bar. /// </summary> public static int GetDecodeIteratorSize(byte[] bytes) { var parser = new GifParser(bytes); return(parser.Blocks.Count(i => i is ImageDescriptor)); }
/// <summary> /// Iterator can be used for large GIF-files in order to display progress bar. /// </summary> public static IEnumerable <GifFrame> DecodeIterator(byte[] bytes) { var parser = new GifParser(bytes); var blocks = parser.Blocks; var width = parser.LogicalScreenDescriptor.LogicalScreenWidth; var height = parser.LogicalScreenDescriptor.LogicalScreenHeight; var globalColorTable = parser.LogicalScreenDescriptor.GlobalColorTableFlag == 1 ? GetUnityColors(parser.GlobalColorTable) : null; //var backgroundColor = globalColorTable?[parser.LogicalScreenDescriptor.BackgroundColorIndex] ?? EmptyColor; GraphicControlExtension graphicControlExtension = null; var state = new Color32[width * height]; var filled = false; for (var j = 0; j < parser.Blocks.Count; j++) { if (blocks[j] is GraphicControlExtension) { graphicControlExtension = (GraphicControlExtension)blocks[j]; } else if (blocks[j] is ImageDescriptor) { var imageDescriptor = (ImageDescriptor)blocks[j]; if (imageDescriptor.InterlaceFlag == 1) { throw new NotSupportedException("Interlacing is not supported!"); } var colorTable = imageDescriptor.LocalColorTableFlag == 1 ? GetUnityColors((ColorTable)blocks[j + 1]) : globalColorTable; var data = (TableBasedImageData)blocks[j + 1 + imageDescriptor.LocalColorTableFlag]; var frame = DecodeFrame(graphicControlExtension, imageDescriptor, data, filled, width, height, state, colorTable); if (_free) { if (frame.Texture.width > 256 || frame.Texture.height > 256) { throw new Exception("The Free version has maximum supported size 256x256 px. Please consider buying the Full version of Power GIF."); } //if (++frames > 20) throw new Exception("The Free version is limited by 20 frames. Please consider buying the Full version of Power GIF."); } yield return(frame); switch (frame.DisposalMethod) { case DisposalMethod.NoDisposalSpecified: case DisposalMethod.DoNotDispose: break; case DisposalMethod.RestoreToBackgroundColor: for (var i = 0; i < state.Length; i++) { state[i] = EmptyColor; } filled = true; break; case DisposalMethod.RestoreToPrevious: // 'state' was already copied before decoding current frame filled = false; break; default: throw new NotSupportedException($"Unknown disposal method: {frame.DisposalMethod}!"); } } } }
private static Gif CompleteDecode(GifParser parser, IDictionary <ImageDescriptor, byte[]> decoded) { var globalColorTable = parser.LogicalScreenDescriptor.GlobalColorTableFlag == 1 ? GetUnityColors(parser.GlobalColorTable) : null; //var backgroundColor = globalColorTable?[parser.LogicalScreenDescriptor.BackgroundColorIndex] ?? EmptyColor; GraphicControlExtension gcExtension = null; var width = parser.LogicalScreenDescriptor.LogicalScreenWidth; var height = parser.LogicalScreenDescriptor.LogicalScreenHeight; var state = new Color32[width * height]; var filled = false; var frames = new List <GifFrame>(); for (var j = 0; j < parser.Blocks.Count; j++) { if (parser.Blocks[j] is GraphicControlExtension) { gcExtension = (GraphicControlExtension)parser.Blocks[j]; } else if (parser.Blocks[j] is ImageDescriptor) { var imageDescriptor = (ImageDescriptor)parser.Blocks[j]; if (imageDescriptor.InterlaceFlag == 1) { throw new NotSupportedException("Interlacing is not supported!"); } var colorTable = imageDescriptor.LocalColorTableFlag == 1 ? GetUnityColors((ColorTable)parser.Blocks[j + 1]) : globalColorTable; var colorIndexes = decoded[imageDescriptor]; var frame = DecodeFrame(gcExtension, imageDescriptor, colorIndexes, filled, width, height, state, colorTable); frames.Add(frame); //if (frames.Count == 1 && globalColorTable != null) //{ // if (gcExtension == null || gcExtension.TransparentColorFlag == 0 || gcExtension.TransparentColorIndex != parser.LogicalScreenDescriptor.BackgroundColorIndex) // { // backgroundColor = globalColorTable[parser.LogicalScreenDescriptor.BackgroundColorIndex]; // } //} switch (frame.DisposalMethod) { case DisposalMethod.NoDisposalSpecified: case DisposalMethod.DoNotDispose: break; case DisposalMethod.RestoreToBackgroundColor: for (var i = 0; i < state.Length; i++) { state[i] = EmptyColor; } filled = true; break; case DisposalMethod.RestoreToPrevious: // 'state' was already copied before decoding current frame filled = false; break; default: throw new NotSupportedException($"Unknown disposal method: {frame.DisposalMethod}!"); } } } return(new Gif(frames)); }
public void GifParser_WithWikipediaExampleGifFile_YieldsExpectedElements() { ////byte# hexadecimal text or ////(hex) value Meaning ////0: 47 49 46 //// 38 39 61 GIF89a Header //// Logical Screen Descriptor ////6: 03 00 3 - logical screen width in pixels ////8: 05 00 5 - logical screen height in pixels ////A: F7 - GCT follows for 256 colors with resolution 3 x 8 bits/primary; the lowest 3 bits represent the bit depth minus 1, the highest true bit means that the GCT is present ////B: 00 0 - background color #0 ////C: 00 - default pixel aspect ratio //// R G B Global Color Table ////D: 00 00 00 0 0 0 - color #0 black ////10: 80 00 00 128 0 0 - color #1 //// : : ////85: 00 00 00 0 0 0 - color #40 black //// : : ////30A: FF FF FF 255 255 255 - color #255 white ////30D: 21 F9 Graphic Control Extension (comment fields precede this in most files) ////30F: 04 4 - 4 bytes of GCE data follow ////310: 01 - there is a transparent background color (bit field; the lowest bit signifies transparency) ////311: 00 00 - delay for animation in hundredths of a second: not used ////313: 10 16 - color #16 is transparent ////314: 00 - end of GCE block ////315: 2C Image Descriptor ////316: 00 00 00 00 (0,0) - NW corner position of image in logical screen ////31A: 03 00 05 00 (3,5) - image width and height in pixels ////31E: 00 - no local color table ////31F: 08 8 Start of image - LZW minimum code size ////320: 0B 11 - 11 bytes of LZW encoded image data follow ////321: 00 51 FC 1B 28 70 A0 C1 83 01 01 ////32C: 00 - end of image data ////32D: 3B GIF file terminator var subject = new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x03, 0x00, 0x05, 0x00, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x21, 0xF9, 0x04, 0x01, 0x00, 0x00, 0x10, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0x00, 0x08, 0x0B, 0x00, 0x51, 0xFC, 0x1B, 0x28, 0x70, 0xA0, 0xC1, 0x83, 0x01, 0x01, 0x00, 0x3B, }; List <GifElement> result; using (var stream = new MemoryStream(subject)) { result = GifParser.ReadGif(stream).ToList(); } Assert.That(result.Count, Is.EqualTo(7)); var header = (Header)result[0]; Assert.That(header.Version, Is.EqualTo("89a")); var logicalScreenDescriptor = (LogicalScreenDescriptor)result[1]; Assert.That(logicalScreenDescriptor.Width, Is.EqualTo(3)); Assert.That(logicalScreenDescriptor.Height, Is.EqualTo(5)); Assert.That(logicalScreenDescriptor.GlobalColorTableFlag, Is.True); Assert.That(logicalScreenDescriptor.SizeOfGlobalColorTable, Is.EqualTo(256)); Assert.That(logicalScreenDescriptor.ColorResolution, Is.EqualTo(8)); Assert.That(logicalScreenDescriptor.BackgroundColorIndex, Is.EqualTo(0)); Assert.That(logicalScreenDescriptor.PixelAspectRatio, Is.Null); var globalColorTable = (GlobalColorTable)result[2]; Assert.That(globalColorTable.Value.Length, Is.EqualTo(256)); Assert.That(globalColorTable.Value, Is.EqualTo( new[] { Color.Black, Color.FromArgb(128, 0, 0) }.Concat(Enumerable.Repeat(Color.Black, 253)).Concat(new[] { Color.White }).ToArray()).Using(ColorComparer)); var graphicsControlExtension = (GraphicsControlExtension)result[3]; Assert.That(graphicsControlExtension.TransparencyFlag, Is.True); Assert.That(graphicsControlExtension.UserInputFlag, Is.False); Assert.That(graphicsControlExtension.DisposalMethod, Is.EqualTo(0)); Assert.That(graphicsControlExtension.DelayTime, Is.EqualTo(0)); Assert.That(graphicsControlExtension.TransparencyIndex, Is.EqualTo(16)); var imageDescriptor = (ImageDescriptor)result[4]; Assert.That(imageDescriptor.Left, Is.EqualTo(0)); Assert.That(imageDescriptor.Top, Is.EqualTo(0)); Assert.That(imageDescriptor.Width, Is.EqualTo(3)); Assert.That(imageDescriptor.Height, Is.EqualTo(5)); Assert.That(imageDescriptor.LocalColorTableFlag, Is.False); Assert.That(imageDescriptor.SortFlag, Is.False); Assert.That(imageDescriptor.InterlaceFlag, Is.False); Assert.That(imageDescriptor.SizeOfLocalColorTable, Is.EqualTo(0)); var raster = (Raster)result[5]; Assert.That(raster.Value.Width, Is.EqualTo(3)); Assert.That(raster.Value.Height, Is.EqualTo(5)); Assert.That(raster.Value.GetPixel(0, 0), Is.EqualTo(Color.Black).Using(ColorComparer)); Assert.That(raster.Value.GetPixel(1, 0), Is.EqualTo(Color.White).Using(ColorComparer)); Assert.That(raster.Value.GetPixel(2, 0), Is.EqualTo(Color.White).Using(ColorComparer)); Assert.That(raster.Value.GetPixel(0, 1), Is.EqualTo(Color.White).Using(ColorComparer)); Assert.That(raster.Value.GetPixel(1, 1), Is.EqualTo(Color.Black).Using(ColorComparer)); Assert.That(raster.Value.GetPixel(2, 1), Is.EqualTo(Color.White).Using(ColorComparer)); Assert.That(raster.Value.GetPixel(0, 2), Is.EqualTo(Color.White).Using(ColorComparer)); Assert.That(raster.Value.GetPixel(1, 2), Is.EqualTo(Color.White).Using(ColorComparer)); Assert.That(raster.Value.GetPixel(2, 2), Is.EqualTo(Color.White).Using(ColorComparer)); Assert.That(raster.Value.GetPixel(0, 3), Is.EqualTo(Color.White).Using(ColorComparer)); Assert.That(raster.Value.GetPixel(1, 3), Is.EqualTo(Color.White).Using(ColorComparer)); Assert.That(raster.Value.GetPixel(2, 3), Is.EqualTo(Color.White).Using(ColorComparer)); Assert.That(raster.Value.GetPixel(0, 4), Is.EqualTo(Color.White).Using(ColorComparer)); Assert.That(raster.Value.GetPixel(1, 4), Is.EqualTo(Color.White).Using(ColorComparer)); Assert.That(raster.Value.GetPixel(2, 4), Is.EqualTo(Color.White).Using(ColorComparer)); var trailer = (Trailer)result[6]; }