C# gif Image to MemoryStream and back (lose animation)

Oliver Bernhardt picture Oliver Bernhardt · Jan 6, 2012 · Viewed 9.5k times · Source

I have a small problem and I do not find any solutions. I want to convert a GIF to a byte[] and then back to a GIF. I works fine but I lose the animation.

It is a perfectly animated GIF when I start (I show it in a PictureBox element). But after conversion I get stuck with the first frame.

HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create("creativetechs.com/i/tip_images/ExampleAnimation.gif");
HttpWebResponse httpWebReponse = (HttpWebResponse)httpWebRequest.GetResponse();
Stream stream = httpWebReponse.GetResponseStream();
Image img = Image.FromStream(stream);

MemoryStream ms = new MemoryStream();
img.Save(ms,img.RawFormat);
byte [] bytes = ms.ToArray();
Image img2 = Image.FromStream(new MemoryStream(bytes));

int frames1 = img.GetFrameCount(System.Drawing.Imaging.FrameDimension.Time);
int frames2 = img2.GetFrameCount(System.Drawing.Imaging.FrameDimension.Time);

I also tried to use not RawFormat but System.Drawing.Imaging.ImageFormat.Gif. Didn't change a thing. frames1 is right number of frames. frames2 is 1.

I have 2 PictureBox elements in my GUI. One showing img and the other img2. But img2 is not animated while img is. What is wrong?

I have also tried to use serialization instead to create my byte[].

I serialized the image and deserialized it again and it didn't change anything either. How is this possible?

Answer

Rasmus Faber picture Rasmus Faber · Jan 17, 2012

When you load your image from a Stream, the .NET framework detects that the GIF is animated. Since it knows that it will be unable to reencode an animated GIF, it tries to store the original encoding of the GIF. But this happens after it has read the stream and decoded the GIF. So when it tries to rewind the stream this fails and it ends up not storing the original.

When you call Save() it first checks whether it has the original encoding stored. But since that operation failed, it attempts to reencode the GIF. Since .NET does not have an encoder for animated GIFs, it only encodes the first frame.

If you use a FileStream instead it works, since a FileStream is seekable.

You can make your code work by loading the response into a MemoryStream first:

// ...
Stream stream = httpWebReponse.GetResponseStream();

MemoryStream memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
memoryStream.Position = 0;
stream = memoryStream;

Image img = Image.FromStream(stream);
// ...

If you want to see what happens, enable .NET reference source debugging and note what happens in Image.EnsureSave(). You will also note that the Image-implementation already copies the Stream into a MemoryStream, so that they could fix the problem by using that instead of the original Stream.