Painting animated images using C#

While reviewing The C# Top 100 it occurred to me that in my own code base I have many bits of code which may make useful blog posts, and that shouldn't take as long to write as the ones I usually create. Plus, I've a fair amount of source code for extending built in controls in various ways, creating new controls from scratch and other useful library code - I need to explore ways of decoupling some of that and releasing it for anyone to use.

To get started with this idea is a simple article on painting animated images using C#. If you assign an animated GIF file to the Image property of a Control, the .NET Framework will take care of animating the image for you. However, it only provides this automatically for the Image property and not for other properties such as BackgroundImage, or any custom image properties you add to your own components.

Fortunately the framework doesn't secret the animation functionality away and provides the static ImageAnimator class (located in System.Drawing) to handle the bulk of the work.

Click the above image to view the animated version. (Image Credit: Dominique Toussaint)

Checking if an image can be animated

The first thing to do is check if an animate can be animated. While calling the various ImageAnimator methods with static images (or even null references) won't crash, if your image is static then there's no need to call them in the first place.

The ImageAnimator.CanAnimate method takes a source Image and returns if it supports animation or not. Passing null to this method will also return false.

private Image _image;
private bool _isAnimating;

_image = LoadImageFromSomewhere();
_isAnimating = ImageAnimator.CanAnimate(_image);

(Image Credit: Vera Kratochvil)

Preparing for animation

If your image supports animation, the next step is to call ImageAnimator.Animate, passing in both the source image and an EventHandler to receive change notifications.

This method will create a background thread that will periodically check watched images and advance frames as required. When it detects a new frame should be painted, it will call the event handler registered for the image, allowing you to handle the update, e.g. repaint your control.

Only one thread is created no matter how many images are being animated

private void SetupAnimation()
{
  _isAnimating = ImageAnimator.CanAnimate(_image);

  if (_isAnimating)
  {
    ImageAnimator.Animate(_image, this.OnFrameChangedHandler);
  }
}

private void OnFrameChangedHandler(object sender, EventArgs eventArgs)
{
  // trigger a repaint of our image
  customPaintPanel.Invalidate();
}

One mistake I sometimes see developers do is calling the Refresh method of a custom Windows Forms control. Calling Refresh will force the control and its children to be repainted immediately. An alternative way is to call Invalidate (without any arguments) which will mark the window to be repainted without forcing the paint or repainting child windows - generally this is more suitable and reduces the number of unneeded repaints.

Halting animation

When you are finished with the source image, you should call ImageAnimator.StopAnimate to remove the image and callback from the list of watched images.

private void CleanUp()
{
  if (_image != null)
  {
    // disable animations
    if (_isAnimating)
    {
      ImageAnimator.StopAnimate(_image, this.OnFrameChangedHandler);
    }

    _isAnimating = false;

    _image.Dispose();
    _image = null;
  }
}

Painting the image

The current frame is part of the Image instance's metadata, so you don't need to do anything specific to paint animated images vs static. With that said, the ImageAnimator class tracks the current frame separately and doesn't update the source Image until requested, which you do by calling ImageAnimator.UpdateFrames.

private void customPaintPanel_Paint(object sender, PaintEventArgs e)
{
  if (_isAnimating)
  {
    ImageAnimator.UpdateFrames(_image);
  }

  e.Graphics.DrawImage(_image, 0, 0);
}

Wrapping up

As you can probably see, this is quite a simple process and makes it easy to support animated graphics in applications that reference System.Drawing.

A complete example demonstrating how to use the ImageAnimator class is available from the link below.

Downloads

Filename Description Version Release Date
DrawAnimatedImage.zip
  • md5: 4a018e6a7814473a37471c9302ac242e

Sample project for the painting animated images blog post.

28/10/2017 Download

About The Author

Gravatar

The founder of Cyotek, Richard enjoys creating new blog content for the site. Much more though, he likes to develop programs, and can often found writing reams of code. A long term gamer, he has aspirations in one day creating an epic video game. Until that time, he is mostly content with adding new bugs to WebCopy and the other Cyotek products.

Leave a Comment

While we appreciate comments from our users, please follow our posting guidelines. Have you tried the Cyotek Forums for support from Cyotek and the community?

Styling with Markdown is supported