Charles Petzold

WPF Ink and Graphics

June 2, 2006
Roscoe, NY

The aspect of Tablet PC programming that has always interested me the most is the intersection of ink and graphics. I barely care about handwriting recognition — Cousin Qwerty and I have been close friends ever since I took a typing course in Jr. High — but show me how to turn ink into a graphics object and I suddenly perk up.

So, it was with great interest that I began exploring the GetGeometry method implemented in the Stroke class from the System.Windows.Ink namespace, which is the where you'll find many WPF tablet-specific classes.

The GetGeometry method returns an object of type Geometry, which is the closest that WPF comes to pure analytic geometry. A Geometry object is just a collection of coordinate points, assembled in a series of connected and disconnected straight lines and curves. In the general case, a Geometry object is a graphics path, and the standard representation of a Geometry object in XAML is called the "PathGeometry Markup Syntax," which was once documented in the Path.Data property but now has its own section in the WPF tutorials. (In the May SDK documentation, it's located at WinFX Development/Windows Presentation Foundation/Graphics and Multimedia/Graphics/Geometries/Overviews/PathGeometry Markup Syntax.)

What's most interesting about the Geometry object returned from the Stroke.GetGeometry method is that it represents not the straight lines and curves you drew with the stylus, but the outline of those straight lines and curves. This outline takes into account the shape and size of the stylus tip — and it can have different horizontal and vertical dimensions and be rotated for some calligraphic effects — and stylus pressure.

How can we get some Stroke objects to try it out? The InkCanvas element is the highest-level approach to Tablet PC programming in the WPF. The InkCanvas retains and renders stylus input and also accepts mouse input, so you don't need a Tablet PC to use it. InkCanvas has several properties to select drawing modes and eraser modes, and stores ink as a StrokeCollection, which has built-in facilities to save and load ink in Ink Serialized Format.

I wrote a little app called YellowPad, which doesn't do much more than demonstrate the standard features of InkCanvas. (It's not even a pad; it's just one page of a pad.) You can install and run this program from the Applications = Code + Markup page of my Web site. All source code for the program will be in the book.

The program also contains a feature based around the Stroke.GetGeometry method. The program allows saving the ink as a XAML DrawingGroup element. This DrawingGroup is a collection of GeometryDrawing objects, which are basically Geometry objects with brushes. The following code in the program converts the strokes into this file. (The inkcanv is an InkCanvas object of course, and file is of type FileStream.)

Notice that highlighter colors are made 50% transparent.

So, once you have this DrawingGroup file, what can you do with it? Well, you can display it with Image. As you may know, Image is the the simplest way to display bitmaps in WPF programs, but its Source property is actually of type ImageSource, and one class that derives from ImageSource is DrawingImage, which you can easily make out of a Drawing.

I used YellowPad to hand-write a copyright notice and then saved it as the file Signature.xaml. I made that file part of the YellowPad project in Visual Studio and gave it a build action of Resource. In the About box class, I loaded the resource and displayed it on the window with the following code (where imgSignature is an Image element defined in XAML):

And that's how you can integrate saved stylus input with other WPF text and graphics.