Category Archives: Tablet

Converting Silverlight InkPresenter images to a PNG file

In the TabletPC SDKs and in WPF it’s very easy to take an ink image and save it to an image format – BMP, JPG, etc.

Then came Silverlight and the InkPresenter and naturally I wanted to do the same. But it wasn’t so easy.

Silverlight itself isn’t bogged down with that functionality. So you first need to get the XAML representation of the Ink and send it to a service where either the TabletPC SDK or the WPF APIs are available. Even then you are not home free because the Silverlight ink is not quite the same as either of the other two. So you then need to extract data from the XAML representation of the Silverlight ink and create a new object for whichever API you choose.

This was all done in Silverlight 1.0. I haven’t pulled this into Silverlight 1.1/2.0 yet, but it should all be the same and you still have to do the conversion on the server side. THe only difference of course, is the javascript needs to be converted to .NET code on the client side.

Even then, there is still some more trickery because there is something strange with using the width from the Silverlight object and I spent hours just experimenting with getting the proportions to display properly in the image. I also spent a lot of time struggling with the colors because the javascript output of the color values doesn’t line up with what WPF wants. You’ll see in the code comments all of the conversions going on.

Once I had all of that worked out (and this represents hours of effort) there were still some issues. Luckily, Stefan Wick, who is the ultimate guru on this topic and finally has a blog – hoorah!, was able to set me straight (and trim some  of my code down significantly).

I hadn’t thought much of this nor, apparently had anyone else, until someone recently emailed asking me how I did it so that he can use it as part of a solution in a competition. (I hope that the requirements of the competition don’t say anything about original work!), so I thought I would blog the steps.

1) Convert the InkPresenter data to XAML . This does two things. FIrst it enables you to serialize it and pass it to a web service and secondly, it is the lowest reasonable common denominator for sharing between different objects. This javascript code comes from Gavin Gear.

This javascript code reads through the StrokeCollection property of an InkPresenter and builds up a string of xml that is the XAML representation of the StrokeCollection. You could also take the resulting string and pass it to CreateFromXAML to recreate the Silverlight StrokeCollection object.

  if (strokeCollection.Count>0)  
{
    var xaml = "<StrokeCollection>";
   if (strokeCollection != null)
   {
for (var i = 0; i < strokeCollection.Count; i++)
{
  var stroke = strokeCollection.GetItem(i);
  if (stroke.Name>"")
    xaml += "<Stroke Name='" + stroke.Name + "'><Stroke.DrawingAttributes>";
  else
    xaml += "<Stroke><Stroke.DrawingAttributes>";
    xaml += "<DrawingAttributes ";
    xaml += "Color='" + BrowserColorConverter
            (stroke.DrawingAttributes.Color) + "' ";
    xaml += "OutlineColor='" + convertColorToHexString
               (stroke.DrawingAttributes.OutlineColor) + "' ";
    xaml += "Width='" + stroke.DrawingAttributes.Width + "' ";
    xaml += "Height='" + stroke.DrawingAttributes.Height + "' ";
    xaml += "/></Stroke.DrawingAttributes>";
    xaml += "<Stroke.StylusPoints>";
    for (var j = 0; j < stroke.StylusPoints.Count; j++)
    {
      var stylusPoint = stroke.StylusPoints.GetItem(j);
      xaml += "<StylusPoint X='" + 
               roundToTwoDecimalPlaces(stylusPoint.X) + "' Y='" +   
roundToTwoDecimalPlaces(stylusPoint.Y) + "' />"; } xaml += "</Stroke.StylusPoints></Stroke>"; } } xaml += "</StrokeCollection>";

2) Pass this string to a web service method that will do the following to it

3) Create a WPF InkObject from the XAML. Now that I’m in the web service, I can use .NET code. Phew. Note that I did this before I knew how to use LINQ to XML so I struggled through XPath to get this. Watch for an upcoming MSDN Mag article that will have updated code.

private static StrokeCollection InkObjectfromXAML(XmlNode StrokeColl)
{
  StrokeCollection objStrokes = new StrokeCollection();
  XmlNodeList strokeElements =StrokeColl.SelectNodes("Stroke");
  foreach (XmlNode strokeNodeElement in strokeElements)
  {
   //step 1: create a new stroke from the stylus point elements in the XAML
    XmlNodeList stylusPointElements = strokeNodeElement
               .SelectNodes("./Stroke.StylusPoints/StylusPoint");
    XmlNode drawAttribs = strokeNodeElement 
               .SelectSingleNode("./Stroke.DrawingAttributes");
    //points node is sent to GetStrokePOints method to convert to a type 
//that can be used by the new stroke
System.Windows.Input.StylusPointCollection strokeData = GetStrokePoints(stylusPointElements); Stroke newstroke = new Stroke(strokeData); //step 2: grab color metadata about stroke from the xaml //color is a hex value //the stroke object requires a System.Windows.Media.Color type //following code performs the conversion string mycolor = drawAttribs.FirstChild.Attributes["Color"].Value; Drawing.Color drwColor = Drawing.ColorTranslator.FromHtml(mycolor); //build the new color from the a,r,g,b values of the drawing.color Windows.Media.Color newColor = new Windows.Media.Color(); newColor.A = drwColor.A; newColor.R = drwColor.R; newColor.G = drwColor.G; newColor.B = drwColor.B; //Step 3: extract width data from xaml, convert to int int myIntWidth; bool parseSuccess = int.TryParse (drawAttribs.FirstChild.Attributes["Width"].Value,
out myIntWidth); //Step 4: apply width & color to stroke //some really wierd unexplainable transformations that I had to get     // around until the final images looked right. if (myIntWidth == 3) newstroke.DrawingAttributes.Width = 1.5; else newstroke.DrawingAttributes.Width = 2; newstroke.DrawingAttributes.Color = newColor; //Step 5: add stroke to the stroke collection objStrokes.Add(newstroke); } return objStrokes; } //The GetStrokePoints method (called from the method above, //is an abstraciton of some sample code from Microsoft.
private static Windows.Input.StylusPointCollection GetStrokePoints(XmlNodeList stylusPointElements) {
Windows.Input.StylusPointCollection pointData = new Windows.Input.StylusPointCollection(); //The object requires HiMetric point values, // create multiplier for conversion double pixelToHimetricMultiplier = (2540d / 96d) / 100; foreach (XmlNode stylusPointElement in stylusPointElements) { string xStr = stylusPointElement.Attributes["X"].Value; string yStr = stylusPointElement.Attributes["Y"].Value; //x and y are in pixels, //we need to multiply them to get them into HIMETRIC //space, which is what the InkAnalyzerBase expects int xInHimetric = (int)(Convert.ToDouble(xStr) * pixelToHimetricMultiplier); int yInHimetric = (int)(Convert.ToDouble(yStr) * pixelToHimetricMultiplier); pointData.Add(new Windows.Input.StylusPoint(xInHimetric, yInHimetric)); } return pointData; }

 Now we have an inkObject that WPF will be happy with!

4) Convert WPF Ink to PNG format bytes This is with a BIG thanks to Stefan – we need to start a separate thread to do the conversion from WPF Ink ojbect to PNG. That conversion happens inside the thread. Also, thank to his deep understanding of the ink object, Stefan was able to accomplish in a much smaller amount of code what I had achieved in about 3 times as much code. I was definitely doing loop-dee-loops, but it was the best I could come up at the time.

Note that I am not saving to an actual file here, just creating the bytes because my goal was to store that in a database.

private static void ThreadforConverttoPNG()
{
  Thread t = new Thread(new ThreadStart(ConverttoPNG));
  t.SetApartmentState(ApartmentState.STA);
// Start ThreadProc.Note that on a uniprocessor, the new 
// thread does not get any processor time until the main thread 
// is preempted or yields.Uncomment the Thread.Sleep that 
// follows t.Start() to see the difference.
t.Start();
   }

private static void ConverttoPNG()
{
  //I had originally achieved this with a LOT more code.
  // This is Stefan's more trimmed down method
  //create temporary InkCanvas
  InkCanvas inkCanvas = new InkCanvas();
  inkCanvas.Strokes = strokes;
  //render InkCanvas to a RenderBitmapTarget
  Rect rect = inkCanvas.Strokes.GetBounds();
  RenderTargetBitmap rtb = new RenderTargetBitmap((int)rect.Right,
          (int)rect.Bottom, 96d, 96d, Windows.Media.PixelFormats.Default);
  rtb.Render(inkCanvas);
  //endcode as PNG
  BitmapEncoder pngEncoder = new PngBitmapEncoder();
  pngEncoder.Frames.Add(BitmapFrame.Create(rtb)); 
  //save to memory stream
  System.IO.MemoryStream ms = new System.IO.MemoryStream(); 
  pngEncoder.Save(ms);ms.Close();strokeBytes= ms.ToArray();
} 

5) My next step was actually to store the bytes into a database. I wasn’t actually saving out to a file. But to do that is simple. System.IO.File lets you create a new file on the fly from a byte array.

   System.IO.File.WriteAllBytes("C:\\myfile.png",strokeBytes); 

So, those are all of the pieces from converting a silverlight inkpresenter image to an image file.

Learn Silverlight Annotation – make a killing in the online advertising market

Yet another Flash driven advertisement (here are some others i’ve blogged about in the past) that uses annotation. Below is a screencast of me playing with this Notes ad (with a mouse, not a stylus). You can do this in Silverlight 1.0 and 1.1 with the InkPresenter. I’ll be giving a session on Annotating in Silverlight as part of the Mobile Connections show during the big DevConnections conference next week (Nov 5 – 8) in Las Vegas.

Silverlight Ink – Searching in Google

Loren Heiny has been working on a cool Silverlight annotation app to user Silverlight and a stylus to do Google and Technorati searches. It’s called SearchTip and is live on TabletPC Post.

There is a lot that is really interesting about this. (And it’s visually appealing too!) First of all, he has a YouTube video where he compares using this (earlier version) on a Mac to using Inkwell on the Mac (when you have a tablet ala Wacom attached to the Mac) and demonstrates the superiority of Microsoft’s handwriting recognition. I was lucky enough to attend an SDR at Microsoft a few years ago where the man who ran the whole reco team explained to us how they made it all work. I can’t imagine anybody being able to come close to their investment or acheivement with handwriting recognition, so it was great to see Loren being able to really compare apples to apples (no pun originally intended, but oh well!)

Next is the fact that Loren is doing handwriting recognition from the InkPresenter in Silverlight. Not an easy feat. Once the reco is done, the result can get passed to a google service and voila you get your results displayed.

Loren has done some amazing work with the Tablet APIs for a number of years and always thinks out of the box. So I love that he’s taking his ideas and applying them to Silverlight.

 

Of course, you don’t need a tabletpc to draw in silverlight, but as awesome as the recognition is, I don’t think it’s fair to ask it to recognize mouse drawn handwriting. But it’s not bad. Reco returns a list of guesses, sorted by best to worst. Here I’m using an earlier version which does google searching and trying it with my mouse on a regular (non-tablet) desktop.

So you can click on the guess (I clicked on Steins) and it will show you the next guess on it’s list. Heinz was next, then a few more clicks (just to see) got me off the track. oops. This is not a reflection of the reco or of Loren’s app. I’m only playing around with the mouse for fun (and laziness since my tablet is upstairs.) So while the reco may not be great when you aren’t using a stylus which has about 10 times the resolution as a mouse, Silverlight’s ability to collect the ink data from the mouse is still pretty impressive.

You can see Loren doing this. and how impressive it truly is using a Tablet, in his YouTube demo video.

You can clear your writing with the x, and of course, when you have the correct reco displayed, click Search.

iTablet… a bigger iPhone?

Last year, there was lots of buzz about a possible iTablet, for example, ZDNet’s Matthew Miller is piecing together some various things he’d been reading. I never really paid much attention to it but now the iPhone has been making me wonder  if the technology that has gone into the iPhone is headed for other things (and if I was paying more attention , that’s probably been said in a thousand blogs, too). Certainly if you google “tablet pc” and apple there’s gobs of speculation – mostly from last year because a patent had been filed at some point. The patent most likely was for the technology in the iPhone. But heck, I have a touch screen tablet pc (Lenovo Thinkpad X60) and yet I’m still drooling over the iPhone (no AT&T in Vermont and I want Mobile 6 anyway and someone also pointed out on a listserv today… that phone’s now cost more than computers!).

I don’t know how Apple would ever come close to what Microsoft has done with the Tablet PC platform though, especially with the hand writing recognition. If I recall correctly, there were over a million samples used to get the recognition algorithms. On my touch screen, I can actually write with my finger (just for fun, and it was Stephen Toub who gave me that idea) and the reco works with that even!

Of course there’s always Surface which is just as droolyas an iPhone  – just can’t put it in your pocket.

Convert Windows Journal notes to Silverlight

The Mobile team is at it again. They have written a converter to take Journal notes and convert them into an interactive Silverlight page. You can read about it on the Mobile dev center and download the converter application. There are two live demos of it here on my own website where I have hosted their sample and one of my own. (Click on the images below to go to the samples.) Note that mine seems to have stretched a bit because I created it on a lower resolution computer.

My Silverlight Ink Experiments: Next Step… try to look like a silverlight application

Inspired by the Scribbler app (part of the Silverlight 1.1 Gallery), written by Daniel Cook  & Pete Blois (with some inspiration from Laurence Moroney)  I decided to spiff up my own drawing application.

Why is it that a black background seems to be the way to make apps look cool?

I even finally opened up Microsoft Expression Blend to help me since I was getting sick of working in raw XAML and having to test each visual change by debugging the app. Last time I looked at this product, it frightened me and I closed it quickly. But now that I have done enough of the hand-coded XAML, it was not a huge leap to comprehend how to use Expression Blend and what I could do with it.

One thing that I discovered is that the Background property of the InkPresenter element, while necessary, is not recognized by the designer. So to do the design in Expression, I had to remove that property, then replace it when I wanted to test out the app.

Since my app is still using the v1.0 of Silverlight (and javascript, not .NET), I can’t pull off the slick color picker that is in the Scribbler app. But when it’s time to move to v1.1, I’ll know where to find the code!

Lenovo X60 Thinkpad Battery problems – will there be a new battery recall?

The battery on my 3 month old Lenovo X60 is dead and I am getting the dreaded notice in the power manager “Irreparable damage to the battery has been detected. Replace the battery with the new one.”

In addition to the message in the Power manager, I have the following symptoms:

  • Battery Indicator light is blinking orange
  • Power status says “Plugged in, not charging”
  • Computer shuts down immediately when unplugged (since the battery is dead).

This is not atypical of old batteries that need replacement, but this battery is fairly new and has not been abused in any way.

I attempted a recommended BIOS update but this requires a fully charged battery.

I checked the March 27th battery recall, but my battery was not on the list.

Luckily, I found a comment thread in the LenovoBlogs under a post that is a few months old called “Power Manager.” There is a new string of comments that began a few days ago with other people having this problem. An IBM technician from Vancouver has joined the thread, identifed the problem and is currently seeking a solution.

So if you have found my blog post via searching for a solution to this problem… keep an eye on the comments on the tail end of this post’s comments: http://www.lenovoblogs.com/insidethebox/?p=52.

I like having found the www.LenovoBlogs.com site. It’s a mini “blogs.msdn.com” and a good stab at corporate transparency and accessibility. The product manager’s direct phone number is even published there!