C#Drawing.Imaging丢弃GIF帧,如果它们相同

时间:2013-07-18 11:55:25

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

我需要加载GIF动画并将它们逐帧转换为位图。为此,我使用Drawing.Imaging库逐帧提取我的GIF文件,然后将每个帧转换为位图。

除了连续帧相同,没有像素差异时,一切正常。图书馆似乎正在放弃这样的框架。

我通过简单的测试得出了这个结论。我创建了一个圆圈的动画,这个圆圈在最后一个圆圈消失的时刻与尚未显示的新圆圈之间暂停,正在增长和缩小。当我播放由我提取的位图组成的动画时,暂停不存在。如果我比较相同帧长但不同数量的相同帧的GIF,则返回的totalframescount值是不同的。我还观察到webbrowsers正确显示相同的连续帧。

  public void DrawGif(Image img)
    {

        FrameDimension dimension = new FrameDimension(img.FrameDimensionsList[0]);
        int frameCountTotal = img.GetFrameCount(dimension);   

        for (int framecount = 0; framecount < frameCountTotal; framecount++)
        {
            img.SelectActiveFrame(dimension, framecount);  

            Bitmap bmp = new Bitmap(img);  //cast Image type to Bitmap

                for (int i = 0; i < 16; i++)
                {
                    for (int j = 0; j < 16; j++)
                    {
                        Color color = bmp.GetPixel(i, j);
                        DrawPixel(i, j, 0, color.R, color.G, color.B);

                    }
                }
  1. 有人遇到过这样的问题吗?
  2. 因为我对C#很陌生 - 有没有办法修改.NET lib?
  3. 也许有一个解决我的问题的方法,我不知道,这不涉及更改库?
  4. 更新的代码 - 结果相同

     public void DrawGif(img)
         {
          int frameCountTotal = img.GetFrameCount(FrameDimension.Time);
           for (int framecount = 0; framecount < frameCountTotal; framecount++)
                {
        img.SelectActiveFrame(FrameDimension.Time, framecount); 
         Bitmap bmp = new Bitmap(img);
    
        for (int i = 0; i < 16; i++)
                {
                    for (int j = 0; j < 16; j++)
                    {
                            Color color = bmp.GetPixel(i, j);
                            DrawPixel(i, j, 0, color.R, color.G, color.B);
    
                    }
    

1 个答案:

答案 0 :(得分:1)

Image未保存重复的框架,因此您必须考虑每个框架的time。以下是一些基于this book in Windows Programming的示例代码,介绍如何获取所有帧和正确的持续时间。一个例子:

public class Gif
{
    public static List<Frame> LoadAnimatedGif(string path)
    {
        //If path is not found, we should throw an IO exception
        if (!File.Exists(path))
            throw new IOException("File does not exist");

        //Load the image
        var img = Image.FromFile(path);

        //Count the frames
        var frameCount = img.GetFrameCount(FrameDimension.Time);

        //If the image is not an animated gif, we should throw an
        //argument exception
        if (frameCount <= 1)
            throw new ArgumentException("Image is not animated");

        //List that will hold all the frames
        var frames = new List<Frame>();

        //Get the times stored in the gif
        //PropertyTagFrameDelay ((PROPID) 0x5100) comes from gdiplusimaging.h
        //More info on http://msdn.microsoft.com/en-us/library/windows/desktop/ms534416(v=vs.85).aspx
        var times = img.GetPropertyItem(0x5100).Value;

        //Convert the 4bit duration chunk into an int

        for (int i = 0; i < frameCount; i++)
        {
            //convert 4 bit value to integer
            var duration = BitConverter.ToInt32(times, 4*i);

            //Add a new frame to our list of frames
            frames.Add(
                new Frame()
                {
                    Image = new Bitmap(img),
                    Duration = duration
                });

            //Set the write frame before we save it
            img.SelectActiveFrame(FrameDimension.Time, i);


        }

        //Dispose the image when we're done
        img.Dispose();

        return frames;
    }
}

我们需要一个结构来保存每个帧的位图和持续时间

//Class to store each frame
public class Frame 
{ 
    public Bitmap Image { get; set; } 
    public int Duration { get; set;} 
}

代码将加载Bitmap,检查它是否为多帧动画GIF。然后循环遍历所有帧以构建一个单独的Frame对象列表,其中包含每个帧的位图和持续时间。简单使用:

var frameList = Gif.LoadAnimatedGif ("a.gif");

var i = 0;
foreach(var frame in frameList)
    frame.Image.Save ("frame_" + i++ + ".png");