Archive

Posts Tagged ‘.NET’

High Res Screenshots of WPF Apps

September 20, 2010 3 comments

A while ago, I needed to take a few screenshots of our Point of Sale system to be printed on a large banner. Unfortunately, ordinary screenshots do not scale well. Since the native resolution of the application is only 1024×768, I got a very blurry image when printed. Not good!

Fortunately, WPF is vector based. This means that it is possible to render your application’s GUI in any resolution or with any DPI setting you like. To do so, we simply use the RenderTargetBitmap class. Its constructor takes the target DPI, size and pixel format. The Render method takes any visual and renders it according to the given settings. The RenderTargetBitmap is a BitmapSource, which can easily be saved with (for example) a PngBitmapEncoder.

// Determine size (if the visual is a UIElement)
UIElement uiElement = visual as UIElement;
if (uiElement != null)
{
  width = (int)uiElement.RenderSize.Width;
  height = (int)uiElement.RenderSize.Height;
}

// Render
var rtb = new RenderTargetBitmap(width, height,
                                 dpiX, dpiY,
                                 PixelFormats.Pbgra32);
rtb.Render(visual);

// Encode and save to PNG file
var enc = new PngBitmapEncoder();
enc.Frames.Add(SBitmapFrame.Create(bmp));
using (var stm = File.Create(filename))
  enc.Save(stm);

The images below show the difference between an ordinary screenshot (right) and a ‘screenshot’ taken with the technique described above (left). It’s clear that the left image is crisp and can be used for high quality printing while the right one quickly becomes pixellated when it is enlarged.

High Resolution Screenshot Ordinary Screenshot

There is one caveat. We need to build this screenshot ability straight into the application itself since that is the only way to get a reference to the Visual we want to render, or is it? Tools such as Snoop, Crack.NET and Mole are able to show the compete visual tree, visual previews, etc. of WPF apps. This got me thinking. Apparently, these tools can somehow hook into or ‘take over’ other apps. I still don’t really get how they do this, but what I do know is that they provide access to any visual within any WPF application. Integrating high res screenshot capabilities in these applications is thus relatively easy.

I’ve done this for Snoop. The result can be downloaded here (just unzip and run).

EDIT: This is now integrated in Snoop (See first comment to this post, thanks Cory!). (Source: http://snoopwpf.codeplex.com/SourceControl/changeset/changes/65551)

This is what you’ll get:

Making screenshots with Snoop

Categories: Uncategorized, WPF Tags: , ,

How to Implement a Property

Below is a code snippet of how we implement non-trivial properties, involving event subscriptions and change notifications (through INotifyPropertyChanged). Unsubscribing from the old value’s events is particularly important to avoid memory leaks.

public Amount BatchAmount
{
  set
  {
    // Do nothing if the value hasn't changed (certainly avoid change notification)
    if (batchAmount == value)
      return;

    // Unsubscribe from the old value's events (prevent memory leak)
    if (batchAmount != null)
      batchAmount.PropertyChanged -= batchAmount_PropertyChanged;

    // Assign the new value
    batchAmount = value ?? new Amount(0, UnitPrice.Unit);

    // Subscribe on the new value's events
    batchAmount.PropertyChanged += batchAmount_PropertyChanged;

    // Notify property changed
    OnPropertyChanged("BatchAmount");
  }
}
Categories: Uncategorized Tags: