Posts Tagged ‘Imaging’

Take Snapshots PART II - Save as animated GIF

Wednesday, April 9th, 2008

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:

withWPFCreated

Take Snapshots of Videos with WPF

Sunday, April 6th, 2008

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"
    xmlns=http://schemas.microsoft.com/winfx/2006/xaml/…
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    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>
          <MediaTimelineSource="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);
  bmp.Render(media);

  JpegBitmapEncoder encoder = new JpegBitmapEncoder();
  encoder.Frames.Add(BitmapFrame.Create(bmp));

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

  Process.Start(filename);
}

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.