| " Only
two things are infinite, the universe and human stupidity, and I'm
not sure about the former."
--Albert Einstein
Think Ink
I don't have a Tablet PC yet, but I expect to be developing for it soon, so I downloaded the Tablet PC SDK and started "fooling around". The new controls that regular PC developers would be interested in are the Ink controls. In particular, the InkPicture control is an extension of the PictureBox that allows one to annotate a picture with the pointing device (stylus, or the mouse on a PC) and the resultant "markup" ink collection (for lack of a better word) can be saved as a part of the image, separately, or with several other options.
This has potential for several applications I am currently working on, including one where a medical or other diagram may need to be annotated by the user, and the results serialized and saved to a database for later inclusion and display in a survey or report. This can also be used for digital image representations of a person's signature and similar uses.
Since this binary serialized image and ink data would likely need to be sent on the wire, I reasoned that data compression would be useful. I recently came upon somebody's C# wrapper on Marcus Oberhumer's excellent LZO compression algorithm, and so I figured this would be as good an opportunity as any to try that out. I also included SharpZipLib, and I stripped out everything except the classes and enumerations necessary for in-memory zip stream compression in order to keep the assembly size to a minimum.
Each operation (plain save with no compression, SharpZipLib zip compression with level 9 - maximum compression, and LZO compression) shows a messagebox with the time in ticks to perform the operation as well as the compressed file size.
I stuck Dr. Dotnetsky's putz on the InkPicture control since I know how everybody would just love the opportunity to scratch all over him. The UI looks like so:
To illustrate some of the code, the key methods in the Form class that save a compressed InkPicture follow:
private void button4_Click(object sender, System.EventArgs e)
{
//save compressed
startTime=DateTime.Now ;
byte[] bytes =
inkPicture1.Ink.Save(Microsoft.Ink.PersistenceFormat.Gif);
Image img =CreateImageWithInk(this.inkPicture1.Ink);
SaveInkImageCompressed( img );
}
private Image CreateImageWithInk(Ink inkToDraw)
{
// Create an image the size of the InkPicture.
Image imageWithInk =
new Bitmap(this.inkPicture1.Image, this.inkPicture1.Size);
// Draw the ink onto it.
Graphics graphicsImage = Graphics.FromImage(imageWithInk);
Renderer renderer = new Renderer();
renderer.Draw(graphicsImage, inkToDraw.Strokes);
graphicsImage.Dispose();
return imageWithInk;
}
private void SaveInkImageCompressed(Image image)
{
MemoryStream memStream = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(memStream, image);
byte[] bytes = memStream.GetBuffer();
byte[] cBytes=null;
if(this.checkBox1.Checked==false)
{
Simplicit.Net.Lzo.LZOCompressor c= new Simplicit.Net.Lzo.LZOCompressor();
cBytes=c.Compress(bytes);
label1.Text="Save Length: " +cBytes.Length.ToString() + " Bytes.";
}
else
{
MemoryStream ms = new MemoryStream();
ICSharpCode.SharpZipLib.Zip.Compression.Deflater defl =
new ICSharpCode.SharpZipLib.Zip.Compression.Deflater(9,false);
Stream s =
new ICSharpCode.SharpZipLib.Zip.Compression.Streams.DeflaterOutputStream(ms,defl);
s.Write(bytes, 0, bytes.Length);
s.Close();
cBytes = (byte[])ms.ToArray();
label1.Text="Save Length: " +cBytes.Length.ToString() + " Bytes.";
}
FileStream stm =
new FileStream(Environment.CurrentDirectory+@"\Test.dat",FileMode.Create);
stm.Write(cBytes,0,cBytes.Length);
stm.Close();
endTime=DateTime.Now;
System.TimeSpan elapsed =endTime-startTime;
MessageBox.Show("Saved in " +elapsed.ToString());
} |
Compression results
As expected, LZO compression achieved comparable size results to zip compression with maximum compression level (9), but in only a fraction of the time. The downside to using this particular LZO implementation is that it wraps a C-style dll and is not 100% managed code. Therefore, to use this on the Compact Framework, for example, one would need to either rewrite the C code to allow for the correct DLLImport marshaling, or rewrite it into a 100% managed code implementation (preferred).
The advantage of compression here is simply that it takes very little time and offers potentially large bandwidth savings. Ink Controls for the Tablet PC also offer handwriting recognition and other features. Download the solution and try it out. (NOTE: You will need the Tablet PC SDK - it has a merge module, but it's too big to distribute that way from an online download like this).
Download the Visual Studio.NET 2003 solution accompanying this article |