2

我正在尝试在我的 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");

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

4

1 回答 1

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);
    }
}
于 2016-03-15T22:06:40.450 回答