Still playing with animated Gif images in C#

On this, the last day of my present job (with nothing to do at all), and looking forward to starting the new one, where I may have very little time for blog-writing, to alleviate the boredom I’ve added a bit to yesterday’s code. Note that it still doesn’t support transparency in the animated Gifs it creates though. (And adding transparency would involve modifying the encoder – not my code – and putting me back where I started on this; something I’ve been trying to avoid.)

I added a parameter to my extension method that converts image collections to Gif files, to support setting the Gif delay. I also added another method to export all the frames from an animated Gif file.

The (RomyView application) source download has been updated with all the new code.

  1. #region Images to Animated Gif Image file
  2.  
  3. /// <summary>Saves the images as frames to an animated Gif Image.</summary>
  4. /// <param name=”images”>The images to save.</param>
  5. /// <param name=”path”>The path of the Gif file to create.</param>
  6. /// <param name=”delay”>The delay between frames, in milliseconds.</param>
  7. /// <param name=”repeat”>The number of times the animation should repeat. Leave this zero
  8. /// for it to loop forever, or specify a value to limit the number of repetitions.</param>
  9. public static void SaveAnimatedGifImage(this IEnumerable<Image> images, string path, int delay = 100, int repeat = 0)
  10. {
  11.     var imageArray = images.ToArray();
  12.  
  13.     using (var stream = new MemoryStream())
  14.     {
  15.         using (var encoder = new BumpKit.GifEncoder(stream, null, null, repeat))
  16.         {
  17.             for (int i = 0; i < imageArray.Length; i++)
  18.             {
  19.                 encoder.AddFrame((imageArray[i] as Bitmap).CopyImage(), 0, 0, TimeSpan.FromMilliseconds(delay));
  20.             }
  21.         }
  22.  
  23.         stream.Position = 0;
  24.  
  25.         using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, Constants.BufferSize, false))
  26.         {
  27.             stream.WriteTo(fileStream);
  28.         }
  29.     }
  30. }
  31.  
  32. /// <summary>Asynchronously saves the images as frames to an animated Gif Image.</summary>
  33. /// <param name=”images”>The images to save.</param>
  34. /// <param name=”path”>The path of the Gif file to create.</param>
  35. /// <param name=”delay”>The delay between frames, in milliseconds.</param>
  36. /// <param name=”repeat”>The number of times the animation should repeat. Leave this zero
  37. /// for it to loop forever, or specify a value to limit the number of repetitions.</param>
  38. public static async Task SaveAnimatedGifImageAsync(this IEnumerable<Image> images, string path, int delay = 100, int repeat = 0)
  39. {
  40.     var imageArray = images.ToArray();
  41.  
  42.     using (var stream = new MemoryStream())
  43.     {
  44.         using (var encoder = new BumpKit.GifEncoder(stream, null, null, repeat))
  45.         {
  46.             for (int i = 0; i < imageArray.Length; i++)
  47.             {
  48.                 encoder.AddFrame((imageArray[i] as Bitmap).CopyImage(), 0, 0, TimeSpan.FromMilliseconds(delay));
  49.             }
  50.         }
  51.  
  52.         stream.Position = 0;
  53.  
  54.         using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, Constants.BufferSize, true))
  55.         {
  56.             await stream.CopyToStreamAsync(fileStream, Constants.BufferSize);
  57.         }
  58.     }
  59. }
  60.  
  61. #endregion
  62.  
  63. #region Animated Gif Image to Images
  64.  
  65. /// <summary>Extracts the frames and the delay for each frame from an animated Gif Image.</summary>
  66. /// <returns>An enumerable of key-value pairs, where the key is the image, and the value is that
  67. /// frame’s delay, in milliseconds.</returns>
  68. public static IEnumerable<KeyValuePair<Image, int>> ExportFrames(this Image gifImage)
  69. {
  70.     if (gifImage.RawFormat.Equals(ImageFormat.Gif) && ImageAnimator.CanAnimate(gifImage))
  71.     {
  72.         var frameDimension = new FrameDimension(gifImage.FrameDimensionsList[0]);
  73.         var frameCount = gifImage.GetFrameCount(frameDimension);
  74.  
  75.         var delay = 0;
  76.         var index = 0;
  77.  
  78.         for (int i = 0; i < frameCount; i++)
  79.         {
  80.             delay = BitConverter.ToInt32(gifImage.GetPropertyItem(20736).Value, index) * 10;
  81.             index += 4;
  82.  
  83.             gifImage.SelectActiveFrame(frameDimension, i);
  84.             yield return new KeyValuePair<Image, int>(gifImage.CopyImage(), delay);
  85.         }
  86.     }
  87. }
  88.  
  89. #endregion

 

Animated Gifs actually support setting the delay interval separately on each individual frame. I don’t support that in my image collection to Gif extension methods, but I do export that meta-data in my Gif image to images extension method.

In the actual application, the code is called when you right-click an animated Gif file. It then exports all the frames to a directory with the name of the Gif file, and saves the delay for each frame in that frame’s file name.

Thus you can use it to extract all the frames of an animated Gif file; then modify them; then select them all and save them to a new animated Gif file.

Advertisements

About Jerome

I am a senior C# developer in Johannesburg, South Africa. I am also a recovering addict, who spent nearly eight years using methamphetamine. I write on my recovery blog about my lessons learned and sometimes give advice to others who have made similar mistakes, often from my viewpoint as an atheist, and I also write some C# programming articles on my programming blog.
This entry was posted in Programming and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s