C# Drawing.Imaging dropping GIF frames if they are identical

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.

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

                    }
                }
  • Does someone encountered such a problem?
  • As I am pretty new to C# - is there a way to modify .NET lib ?
  • Maybe there is a solution to my problem that I am not aware of, that does not involve changing the library?
  • 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);
    
                    }
    

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

    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");
    
    链接地址: http://www.djcxy.com/p/84138.html

    上一篇: GetObject返回奇怪的大小

    下一篇: C#Drawing.Imaging删除GIF帧,如果它们是相同的