Take Snapshots PART II – Save as animated GIF

I was asked, if it would be possible to save the snapshots created in my last post as an animated gif. With a DispatcherTimer and the GifBitmapEncoder-class you’re not far away from it. Just create a MediaElement in your Window:

<MediaElement Source="thomasOnBoard.wmv" 
  x:Name="media" MediaOpened="media_MediaOpened"
  MediaEnded="media_MediaEnded" Width="300"
  Height="200" Stretch="Fill"/>

In the Codebehind-File, implement Eventhandlers for MediaOpened and MediaEnded-Events. In MediaOpened you start the DispatcherTimer. I’ve just used an interval of 100 milliseconds. In the Tick-Eventhandler, which is called each 100 milliseconds, a BitmapFrame is added to the GifBitmapEncoders Frames-Property. When the video ends, the MediaEnded-Eventhandler writes the GIF to your disk and opens the file. That’s it. :-)

public partial class Window1 : Window
... GifBitmapEncoder _encoder; DispatcherTimer _timer; private void media_MediaOpened(object sender, ...) { _timer = new DispatcherTimer(); _timer.Interval = TimeSpan.FromMilliseconds(100); _timer.Tick += OnTick; _timer.Start(); } void OnTick(object sender, EventArgs e) { Size dpi = new Size(96, 96); RenderTargetBitmap bmp = new RenderTargetBitmap(300, 200, dpi.Width, dpi.Height, PixelFormats.Pbgra32); bmp.Render(media); if (_encoder == null) _encoder = new GifBitmapEncoder(); _encoder.Frames.Add(BitmapFrame.Create(bmp)); } private void media_MediaEnded(object sender, ...) { _timer.Tick -= OnTick; _timer = null; string filename = Guid.NewGuid().ToString() + ".gif"; FileStream fs = new FileStream(filename, FileMode.Create); _encoder.Save(fs); fs.Close(); _encoder = null; Process.Start(filename); } }

Here’s the gif saved from my video. Just click on it to see it animated:


Take Snapshots of Videos with WPF

With WPF’s Imaging-Classes you can take snapshots of any Visual. The snapshot can be saved in any common Image-Format, like e.g. JPG. Let’s take a look at a pretty short example, that shows how easy this can be done. The example takes snapshots of a Video.

The following Window contains a MediaElement and a Button. The MediaElement plays the Video thomasOnBoard.wmv. The Button defines an Eventhandler for the Click-Event. It takes a snapshot of the video, when you click it.

<Window x:Class="SnapShots.Window1"
    Title="Window1" Height="300" Width="300"
ResizeMode="NoResize"> <StackPanel> <MediaElement x:Name="media" Height="200" Stretch="Fill"> <MediaElement.Triggers> <EventTrigger RoutedEvent="MediaElement.Loaded"> <BeginStoryboard> <Storyboard> <MediaTimeline
Source="thomasOnBoard.wmv" RepeatBehavior="Forever"/> </Storyboard> </BeginStoryboard> </EventTrigger> </MediaElement.Triggers> </MediaElement> <Button Click="Button_Click" Content="Snapshot"/> </StackPanel> </Window>

Let’s look at the Eventhandler of the Button. An instance of the RenderTargetBitmap-class is created with some parameters about image-size, dots per inch (dpi) and Pixelformat. The Render-Method gets the MediaElement as a parameter, so MediaElements visual appearance is stored in the RenderTargetBitmap in memory. With a JpegBitmapEncoder and a FileStream the Image is written as a JPG to disk. That’s it.

void Button_Click(object sender, RoutedEventArgs e)
  Size dpi = new Size(96,96);
  RenderTargetBitmap bmp = 
    new RenderTargetBitmap(300, 200, 
      dpi.Width, dpi.Height, PixelFormats.Pbgra32);

  JpegBitmapEncoder encoder = new JpegBitmapEncoder();

  string filename = Guid.NewGuid().ToString()+".jpg";
  FileStream fs = new FileStream(filename,FileMode.Create);


Instead of taking the picture in the Button_Click eventhandler, you could create a Timer and take an Image every 0.1s. That allows you to extract an image-sequence of your videos. As it works for any Visual, and everything that’s on the screen in a WPF-Application is a visual, there are many things you can do with it. You could create a snapshot of an Image drawn to an inkCanvas, upload it to a webserver to display it on a webpage etc.