Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

WPF GIF Animation

0.00/5 (No votes)
21 Apr 2010 1  
This article shows the best way to play GIF animation in your WPF project.

Introduction

As I think many of us know, a standard set of WPF does not support animated GIF files. At the moment there are several approaches to solving this problem, but many of them have their own drawbacks - or take up a lot of CPU time, or take up a lot of resources. I designed and implemented its decision.

Background

My solution depends on working with System.Threading.Timer class, which helps me to organize succession of frames. But each frame has its own delay value. I decide to read it by parsing the GIF file with ParseGif class. So, the result is only consistent change frames, pre-freeze them in order to avoid memory leaks. More on how to prevent memory leaks, you can find in this remarkable article - Finding Memory Leaks in WPF-based applications.

Using the Code

Let's take a look.

Our solution is divided into two projects - a project of the class of animation, and project testing capabilities. I want to concentrate on the project testing. I did not add that there is one animation file - it would not display anything. I decided to add 100 smileys in the RichTextBox, which in this context, I think is the best option for demonstrating performance.

So, here is the main function LoadSmile of loading animation:

private static void OnAnimatedBitmapChanged
    (DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            AnimatedImage control = (AnimatedImage)obj;

            control.UpdateAnimatedBitmap();

            RoutedPropertyChangedEventArgs<bitmap> e = 
		new RoutedPropertyChangedEventArgs<bitmap>(
                (Bitmap)args.OldValue, 
        (Bitmap)args.NewValue, AnimatedBitmapChangedEvent);
            control.OnAnimatedBitmapChanged(e);
        }

        public static readonly RoutedEvent AnimatedBitmapChangedEvent = 
        EventManager.RegisterRoutedEvent(
            "AnimatedBitmapChanged", RoutingStrategy.Bubble,
            typeof(RoutedPropertyChangedEventHandler<bitmap>), typeof(AnimatedImage));

...

        public void LoadSmile(Bitmap bitmap)
        {
            this.AnimatedBitmap = bitmap;
        }    

Then when you change the image, processing function is executed. In it, we are performing and disassembling GIF file and start the timer, which change the frames.

private void UpdateAnimatedBitmap()
        {
            try
            {
                int nTimeFrames = GetFramesCount(); //get frames count
                _nCurrentFrame = 0; //Set current frame to default value
                if (nTimeFrames > 0) //this is animated file
                {
                    MemoryStream stream = new MemoryStream();
                    AnimatedBitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Gif);
                    stream.Seek(0, SeekOrigin.Begin);
                    byte[] buffer = new byte[stream.Length];
                    stream.Read(buffer, 0, buffer.Length);
                    ParseGif(buffer);
                    _BitmapSources = new List<bitmapsource>(nTimeFrames);
                    stream.Dispose();
                    FillBitmapSources(nTimeFrames);
                    timer = new Timer(OnFrameChanged, null, -1 , -1); //Initialize timer
                    StartAnimate(); //start animation
                }
                else //this is single image
                {
                    Bitmap bitmap = new Bitmap(AnimatedBitmap);
                    _BitmapSources = new List<bitmapsource>(1);
                    _BitmapSources.Add(CreateBitmapSourceFromBitmap(bitmap));
                    Source = _BitmapSources[0];
                }
            }
            catch { }
        }

In the attached project at the beginning of the article, you can find some of the functions carried out in this code. As you can see, the architecture of the decision is not very hard. We could use the built-in Windows Forms class ImageAnimator, but as practice for large-scale solutions in WPF, this class is poorly suited.

I think the most striking example of this model is the program for a chat. Often, it must be enforced at the same time tens of smiles. Naturally, this should not upload a lot of resources and CPU time for the comfort of the client.

Finally, I think of bringing the code in which there is a succession of frames.

 private void OnFrameChanged(object obj)
        {
            try
            {
                Dispatcher.BeginInvoke(DispatcherPriority.Render, 
            new VoidDelegate(delegate { ChangeSource(); }));
            }
            catch { }
        }

        void ChangeSource()
        {
            try
            {
                timer.Change(Delays[_nCurrentFrame] 
            * 10, 0); //get the current delay for the frame
                Source = _BitmapSources[_nCurrentFrame++]; //make it visible
                _nCurrentFrame = _nCurrentFrame % 
            _BitmapSources.Count; //compute the next frame index
            }
            catch { }
        }

Also, our class implemented IDisposable interface which allows you to free resources when smile is unneeded:

public void Dispose()
        {
            try
            {
                timer.Change(-1, -1);
                timer.Dispose();
                _BitmapSources.Clear();
                Source = null;
            }
            catch { }
        }

In principle, I think you will understand the main idea of this code.
In the attached file, you can find the rest of the code and a very easy project for testing.

Conclusion

In this article, I tried to describe the possibility of not displaying an animated file somehow, but to show the possibility of creating a code that can truly withstand high pressures and great economical resource, avoiding memory leaks.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here