C# Drawing.Imaging 丢弃 GIF 帧(如果它们相同) [英] C# Drawing.Imaging dropping GIF frames if they are identical

查看:30
本文介绍了C# Drawing.Imaging 丢弃 GIF 帧(如果它们相同)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need to load GIF animations and convert them frame by frame to bitmaps. To do that, I am extracting my GIF file frame by frame using Drawing.Imaging library and then casting each frame to bitmap.

除了连续帧相同的时候,没有像素差异的时候,一切都很好.图书馆似乎正在丢弃这样的帧.

Everything works just fine except the times when the consecutive frames are the same, when there is no pixel difference. The library seems to be dropping such frames.

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

I came to that conslusion with a simple test. I have created an animation of a circle that is growing and shrinking with a pause between the moment the last circle dissapears and the new one is not yet shown. When I play the animation consisting of my extracted bitmaps that pause is not present. If I compare the GIFs of the same frame-length but different amounts of identical frames, the returned totalframescount value is different. I have also observed that webbrowsers display identical consecutive frames correctly.

  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 库?
  3. 也许有我不知道的问题的解决方案,不涉及更改库?

更新代码 - 结果是一样的

Updated code - the result is the same

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

                }

推荐答案

Image 不保存重复的帧,所以你必须把 时间 考虑每一帧.下面是一些基于 关于Windows编程的书=0x5100%20ofolf>如何获得所有帧和正确的持续时间.一个例子:

The Image is not saving duplicate frames, so you have to take the time of each frame into account. Here is some sample code based on this book in Windows Programming on how to get all the frames and the correct duration. An example:

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

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

We need a structure to save the Bitmap and duration for each Frame

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

代码会加载一个Bitmap,检查是否是多帧动画GIF.然后它循环遍历所有帧以构造一个单独的 Frame 对象列表,这些对象保存每个帧的位图和持续时间.简单使用:

The code will load a Bitmap, check whether it is a multi-frame animated GIF. It then loops though all the frames to construct a list of separate Frame objects that hold the bitmap and duration of each frame. Simple use:

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

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

这篇关于C# Drawing.Imaging 丢弃 GIF 帧(如果它们相同)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆