VB and Tablet PC: Inking on Irregular Surfaces

Published 18 April 07 08:46 PM

So I was playing around with my tablet PC application this evening because someone in a Visual Basic list had posted a question about how to create an irregular drawing surface for a medical application they were working on. They wanted users to be able to draw on a picture of a body, but did not want to collect the ink anywhere outside of the body shape. It actually turned out to be relatively easy. But some background first...

The Tablet PC SDK comes with a couple designable controls called InkPicture and InkEdit. You can drop these controls onto your form and they will immediately start capturing ink. The InkEdit will also convert your ink to text.

These controls make it extremely easy to work with ink. For instance, here’s how we can save just the ink we draw on the InkPicture into a file:

Private Sub SaveInk(ByVal filename As String, ByVal format As Microsoft.Ink.PersistenceFormat)

    Try

        Dim inkData As Byte() = Me.InkPicture1.Ink.Save(format, Microsoft.Ink.CompressionMode.Default)

        

        With My.Computer.FileSystem

            If .FileExists(filename) Then

                .DeleteFile(filename)

            End If

            .WriteAllBytes(filename, inkData, False)

        End With

 

        MsgBox(String.Format("Saved ink data to {0}", filename), MsgBoxStyle.Information)

 

       

    Catch ex As Exception

        MsgBox(String.Format("Unable to save ink data to {0}", filename))

    End Try

 

End Sub

The persistence format can even be specified as a Gif format so you can create a completely new picture of just your annotations. To load the annotations, we just read in the bytes and then load them into a new Ink.Ink object and set it to the Ink property of our InkPicture:

Private Sub LoadInk(ByVal filename As String)

    Dim inkData As Byte() = Nothing

 

    Try

        With My.Computer.FileSystem

            If .FileExists(filename) Then

                inkData = .ReadAllBytes(filename)

            End If

        End With

    Catch ex As Exception

        MsgBox(String.Format("Unable to load ink data from {0}", filename))

    End Try

 

    If inkData IsNot Nothing Then

        Dim newink As New Microsoft.Ink.Ink

        newink.Load(inkData)

        Me.InkPicture1.InkEnabled = False

        Me.InkPicture1.Ink = newink

        Me.InkPicture1.InkEnabled = True

    End If

End Sub

When we want to save both the picture and the ink we just have to create a new picture and then render the ink on the picture using the Ink.Renderer object:

Private Sub SaveInkOnPicture(ByVal filename As String)

    Try

        'Create graphics object

        Dim bm As New Bitmap(Me.InkPicture1.Image)

        Dim g As Graphics = Graphics.FromImage(bm)

 

        'Create a renderer to draw ink on the graphics surface

        Dim r As New Microsoft.Ink.Renderer()

        r.Draw(g, Me.InkPicture1.Ink.Strokes)

 

        'Save the new image

        bm.Save(filename, System.Drawing.Imaging.ImageFormat.Bmp)

 

        MsgBox(String.Format("Saved picture to {0}", filename), MsgBoxStyle.Information)

 

    Catch ex As Exception

        MsgBox(String.Format("Unable to save picture to {0}", filename))

    End Try

 

End Sub

These designable controls are really easy to use and will get you up and running quickly, however what if you want to draw on something other than a picture? That’s where the InkOverlay object comes in. You can use this object to wrap any windows Control to enable inking. For instance, to create a blank “drawing surface” you can use a Panel with the InkOverlay:

Private WithEvents overlay As InkOverlay

 

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    overlay = New InkOverlay(Me.Panel1)

    overlay.Enabled = True

End Sub

 

So now back to the original question about inking on an irregular surface. Well since the InkOverlay can be used to wrap any control, and we can draw any control any way we want, it’s actually pretty easy to achieve this. Since this was a medical application I first found I picture of a human body. I then threw a panel on a form and set its background image to the picture of the body. Next, I added an event handler to the Paint event in order to draw the panel how I wanted to. The key is setting up a GraphicsPath and then creating a new Region along that path for the control.

Public Class Form2

 

    Private WithEvents overlay As Microsoft.Ink.InkOverlay

 

    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        overlay = New Microsoft.Ink.InkOverlay(Me.Panel1)

        overlay.DefaultDrawingAttributes.Color = Color.Red

        overlay.Enabled = True

    End Sub

 

    Private Sub Panel1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint

        Dim Person As New System.Drawing.Drawing2D.GraphicsPath()

        Person.AddEllipse(82, 1, 74, 74)

        Person.AddLine(65, 75, 175, 75)

        Person.AddLine(175, 75, 250, 240)

        Person.AddLine(250, 240, 210, 260)

        Person.AddLine(210, 260, 170, 180)

        Person.AddLine(170, 180, 175, 440)

        Person.AddLine(175, 440, 145, 440)

        Person.AddLine(145, 440, 127, 245)

        Person.AddLine(127, 245, 105, 440)

        Person.AddLine(105, 440, 70, 440)

        Person.AddLine(70, 440, 80, 180)

        Person.AddLine(80, 180, 35, 260)

        Person.AddLine(35, 260, 1, 240)

        Person.AddLine(1, 240, 65, 75)

 

        Me.Panel1.Region = New Region(Person)

    End Sub

End Class

The graphics path I created here is pretty basic but it illustrates the idea. Now when users draw on the panel, it will only allow ink on the graphics path!

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Beth Massi Sharing the goodness that is VB VB and Tablet PC Inking | Insomnia Cure said on June 8, 2009 6:10 PM:

PingBack from http://insomniacuresite.info/story.php?id=3664

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required

About Beth Massi

Beth is a Program Manager on the Visual Studio Community Team at Microsoft and is responsible for producing and managing content for business application developers, driving community features and team participation onto MSDN Developer Centers (http://msdn.com), and helping make Visual Studio one of the best developer tools in the world. She also produces regular content on her blog (http://blogs.msdn.com/bethmassi), Channel 9, and a variety of other developer sites and magazines. As a community champion and a long-time member of the Microsoft developer community she also helps with the San Francisco East Bay .NET user group and is a frequent speaker at various software development events. Before Microsoft, she was a Senior Architect at a health care software product company and a Microsoft Solutions Architect MVP. Over the last decade she has worked on distributed applications and frameworks, web and Windows-based applications using Microsoft development tools in a variety of businesses. She loves teaching, hiking, mountain biking, and driving really fast.

This Blog

Syndication

Page view tracker