GIF 到 PNG:仅提取第一帧

GIF to PNGs: only first frame extracted

我正在尝试在我的 C# 程序中提取动画 gif 的各个帧。

它为每一帧创建一个 png - 效果很好,但是它们只是第一帧的一堆副本。 我做错了什么?

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());
}


更新: 经过一些修补后,我发现它可以工作,如果使用这个:

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

有人可以向我解释一下,为什么这个有效而原始代码无效?
非常感谢!

我认为主要问题是您在不重置的情况下写入同一个内存流。因此,您实际上是在将所有先前提取的文件的内容写到每个新帧中。对于每个图像,只有第一帧是可见的。

您将不得不为每个图像分配一个新的内存流,而不是在一开始就这样做。

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());
    }
}

另一方面,您根本不需要创建内存流,直接写入文件即可。

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);
    }
}