Click here to Skip to main content
15,867,453 members
Articles / Desktop Programming / WPF

Another approach to animated GIF in WPF, with transparency

Rate me:
Please Sign up or sign in to vote.
4.09/5 (8 votes)
31 Oct 2008CPOL3 min read 113.4K   7.5K   37   17
Demonstrates the use of animated GIFs in WPF applications.

WpfAnimatedControlScreenshot.jpg

Introduction

In spite of reach support of animation in WPF, I have not found a quick and easy way to insert animated GIFs in a WPF application. After some searching in the net and analyzing the gathered information, I have assumed that every public available solution has one ore more of the following disadvantages:

  1. Use of unsafe code (yes, back to good old BitBlt!)
  2. Thread unsafe.
  3. No or incomplete support of WPF layout, stretching, zoom, etc.
  4. No support for transparency.
  5. Not supported in XAML.
  6. Impossible to use “embedded” resources (only external GIF files supported).
  7. Too complicated and “heavy” design (for example, browser control with dynamically generated content, etc.)

This article presents my trial to solve the problem, taking into account the above mentioned issues. Hope that a future version of the framework brings us such functionality by default.

How it works and design of the code

The main idea is just simple: extend the standard WPF Image control to accept animated GIF, split the GIF into frames, constructing BitmapSources from each frame and keeping them “inside”, then dynamically switching sources to simulate animation.

Let’s look a bit deeper in code: I have created a custom control AnimatedImage, based on the WPF Image control, with an additional Dependency Property AnimatedBitmap of type Bitmap. This saves the full functionality of the original WPF image like scaling, layout, events etc., and makes it easy to set everything directly from XAML. The custom routed event AnimatedBitmapChanged was registered to provide some extra initialization/cleanup during setting the source GIF, if necessary. Actually, the main functionality is concentrated in the following function:

C#
private void UpdateAnimatedBitmap()
{
  int nTimeFrames = AnimatedBitmap.GetFrameCount
        (System.Drawing.Imaging.FrameDimension.Time);
  _nCurrentFrame = 0;
  if (nTimeFrames > 0)
  {
    _BitmapSources = new BitmapSource[nTimeFrames];
    for (int i = 0; i < nTimeFrames; i++)
    {
      AnimatedBitmap.SelectActiveFrame(
           System.Drawing.Imaging.FrameDimension.Time, i);
      Bitmap bitmap = new Bitmap(AnimatedBitmap);
      bitmap.MakeTransparent();
      _BitmapSources[i] = 
        System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
         bitmap.GetHbitmap(),
         IntPtr.Zero,
         Int32Rect.Empty,
         System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
     }
     StartAnimate();
   }
}

Here, the frames are retrieved from the source GIF, then each frame is made transparent, converted to a BitmapSource, and saved into an internal buffer. Finally, we call the StartAnimate() helper to start the animation process. For controlling animation, an internal ImageAnimator control is used, with the ChangeSource() callback, doing nothing but just switching the active source of the Image control and sending an update appearance request. The BeginInvoke used here is for thread safety.

C#
private delegate void VoidDelegate();

private void OnFrameChanged(object o, EventArgs e)
{
  Dispatcher.BeginInvoke(DispatcherPriority.Render, 
        new VoidDelegate(delegate { ChangeSource(); }));
}

void ChangeSource()
{
  Source = _BitmapSources[_nCurrentFrame++];
  _nCurrentFrame = _nCurrentFrame % _BitmapSources.Length;
  ImageAnimator.UpdateFrames();
}

As I mentioned, there are also two helpers StartAnimate() and StopAnimate() and a property IsAnimating to give the basic control over the AnimatedImage.

C#
public void StopAnimate()
{
  if (_bIsAnimating)
  {
    ImageAnimator.StopAnimate(AnimatedBitmap, 
         new EventHandler(this.OnFrameChanged));
    _bIsAnimating = false;
  }
}

public void StartAnimate()
{
  if (!_bIsAnimating)
  {
    ImageAnimator.Animate(AnimatedBitmap, 
                  new EventHandler(this.OnFrameChanged));
    _bIsAnimating = true;
  }
}

private bool _bIsAnimating;
public bool IsAnimating
{
   get { return _bIsAnimating; }
}

Using the code

Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.

Step 1a. Using this custom control with sources:

  • Add the WpfAnimatedControl project to your workspace.
  • Add the XmlNamespace attribute to the root element of the markup file where it is to be used:
  • XML
    xmlns:MyNamespace="clr-namespace:WpfAnimatedControl"

Step 1b. Using this custom control as DLL:

Add the XmlNamespace attribute to the root element of the markup file where it is to be used:

XML
xmlns:MyNamespace="clr-namespace:WpfAnimatedControl;assembly=WpfAnimatedControl"

You will also need to add a project reference from the project where the XAML file lives to this assembly, and Rebuild to avoid compilation errors.

Step 2. Go ahead and use your control in the XAML file.

To add AnimatedImage to a window, insert the following line to your window XAML file, for example, as shown below:

XML
< MyNamespace:AnimatedImage Name="aimg" 
    AnimatedBitmap="{x:Static code:Resources.wrong}" 
    Stretch="None" AnimatedBitmapChanged="aimg_AnimatedBitmapChanged"/>

Here we assume that you already insertedthe GIF in the window resources.

The provided test application (VS2008, Framework 3.5) demonstrates the common use of the control, and also setting the GIF from an external file.

Warning

Be careful to set the Source property together with the AnimatedBitmap property from XAML; generally, it was designed to use Source only if no animation runs. I.e., if you need a static picture, better use the original WPF Image, and do not set the Source if you are using the AnimatedImage control.

Conclusion

This is only a very basic implementation of an animated image control, but could save a lot of time if you need to “just show a transparent animated GIF”. Feel free to extend it with extra validation, functionality, and so on.

History

  • 31.10.2008: Initial release.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionError in AnimatedBitmap="{x:Static code:Resources.wrong}" on Visual Studio 2019 Pin
Ejrr108529-Aug-22 9:40
Ejrr108529-Aug-22 9:40 
QuestionBinding error Pin
devvvy15-Jun-15 17:31
devvvy15-Jun-15 17:31 
QuestionMemory leak Pin
Member 331922520-Jan-15 3:46
Member 331922520-Jan-15 3:46 
QuestionUse of pack uri Pin
bhaash19-Sep-13 22:52
bhaash19-Sep-13 22:52 
BugIgnores the frame's display interval. Pin
tehcrash21-Jul-12 19:08
tehcrash21-Jul-12 19:08 
This work great on gifs which have frames of equal display time, but misplays gifs with frames of varying intervals.

For example, I have a gif of five frames. The first four frames should display for 0.05 seconds, and the last should display for 3 seconds. However, this will play all of them at 0.05 seconds each.
GeneralMy vote of 5 Pin
Rupesh Kumar Swami17-Mar-12 0:45
Rupesh Kumar Swami17-Mar-12 0:45 
QuestionSpeed problem Pin
Member 471711425-Feb-12 18:40
Member 471711425-Feb-12 18:40 
Generalthanx Pin
manura198526-Jan-12 20:41
manura198526-Jan-12 20:41 
GeneralMy vote of 5 Pin
Member 471711414-Jan-12 18:16
Member 471711414-Jan-12 18:16 
GeneralMy vote of 5 Pin
Guenter Wolf26-Apr-11 10:24
Guenter Wolf26-Apr-11 10:24 
GeneralError 18 Unknown build error, 'Key cannot be null Pin
pevans432114-Nov-10 14:43
pevans432114-Nov-10 14:43 
GeneralLeaking? [modified] Pin
chaf270128-Apr-09 5:51
chaf270128-Apr-09 5:51 
GeneralThreading issues... Pin
rlrcstr6-Mar-09 17:19
rlrcstr6-Mar-09 17:19 
GeneralRe: Threading issues... Pin
Lecha6-Apr-09 1:49
Lecha6-Apr-09 1:49 
GeneralThank you Lecha. Here is a modified version to support both animated and stills. [modified] Pin
fnorum2-Jan-09 7:34
fnorum2-Jan-09 7:34 
GeneralRe: Thank you Lecha. Here is a modified version to support both animated and stills. [modified] Pin
Member 471711416-Feb-12 7:40
Member 471711416-Feb-12 7:40 
GeneralRe: Thank you Lecha. Here is a modified version to support both animated and stills. [modified] Pin
Member 471711417-Feb-12 2:07
Member 471711417-Feb-12 2:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.