GIF到PNG:仅提取第一帧

时间:2016-03-15 21:39:50

标签: c# animated-gif system.drawing.imaging

我正在尝试在c#programm中提取动画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");

有人可以向我解释,为什么这样做有原因并且原始代码没有?
非常感谢你!

1 个答案:

答案 0 :(得分:2)

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

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

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