000000000000000000000
000000000000000000000

Reputation: 1467

GIF to PNGs: only first frame extracted

I am trying to extract the individual frames of an animated gif in my c# programm.

It creates a png for each frame - that works just fine, however they are just a bunch of copies of the first frame. What did I do wrong?

Image img = Image.FromFile(path);
FrameDimension dimension = new FrameDimension(img.FrameDimensionsList[0]);
int frameCount = img.GetFrameCount(dimension);
MemoryStream memory = new MemoryStream();
for(int i = 0; i < frameCount; i++){
    img.SelectActiveFrame(dimension, i);
    ((Image)img.Clone).Save(memory, System.Drawing.Imaging.ImageFormat.Png);
    File.WriteAllBytes(myFolder + "/frame_"+i+".png", memory.ToArray());
}


Update: After some tinkering I found out that it works, if use this:

Bitmap bmp = new Bitmap(img);
bmp.Save(Application.dataPath + projectFolder.Substring(6) + "/frame_"+i+".png");

Can somebody please explain to me, why this works and the original code does not?
Thank you very much!

Upvotes: 2

Views: 1053

Answers (1)

Jeff Mercado
Jeff Mercado

Reputation: 134841

I think the main problem is that you're writing to the same memory stream without resetting it. So you're effectively writing out the contents of all of the previously extracted files to each new frame. And for each image, only the first frame is visible.

You would have to allocate a new memory stream for each image, rather than doing it at the beginning.

for(int i = 0; i < frameCount; i++)
{
    img.SelectActiveFrame(dimension, i);
    var outputPath = myFolder + "/frame_"+i+".png";
    using (var memory = new MemoryStream())
    {
        img.Save(memory, ImageFormat.Png); // cloning is not necessary
        File.WriteAllBytes(outputPath, memory.ToArray());
    }
}

On the other hand, you don't need to create the memory stream at all, just write to the file directly.

var path = ...;
var dir = ...;
using (var img = Image.FromFile(path))
{
    var dimension = new FrameDimension(img.FrameDimensionsList.First());
    var frameCount = img.GetFrameCount(dimension);
    foreach (var i in Enumerable.Range(0, frameCount))
    {
        img.SelectActiveFrame(dimension, i);
        var outputFile = Path.Combine(dir, $"frame_{i:00}.png");
        img.Save(outputFile, ImageFormat.Png);
    }
}

Upvotes: 2

Related Questions