I was chatting with another member of TriNug last night and we talked about the best way to capture a user’s signature. There are some pretty good articles out there, including this one. I dove right in with a WinForm application and a Panel control and built something like this:

Visual Studio 2010 and WinForms made this a pretty straightforward task. First, I built up my domain model starting with the points that are captured from the Panel.MouseMove event handler (MouseEventArgs) with the e.Location of type Point.
I created a Line class that has 2 points that make up the line:
[Serializable]
public class Line
{
public Line()
{
}
public Line(Point startPoint, Point endPoint)
{
this.StartPoint = startPoint;
this.EndPoint = endPoint;
}
public Point StartPoint { get; set; }
public Point EndPoint { get; set; }
}
I then created a Glyph class that is a collection of those lines:
[Serializable]
public class Glyph
{
public Glyph()
{
this.Lines = new List<Line>();
}
public List<Line> Lines { get; set; }
}
I could have called this class “letter” but each glyph may or may not be a letter – it could be several letters strung together in cursive, a part of a letter (the dot of the i), or may not be any letter (like when R2D2 signs his name. R2D2 is a boy, right?)
Anyway, I then created a Signature class that is a collection of glyphs:
[Serializable]
public class Signature
{
public Signature()
{
this.Glyphs = new List<Glyph>();
}
public List<Glyph> Glyphs { get; set; }
}
If this was used in a real-world application, this class would have a uniqueId so you can relate it back to your people/user class. It might have some other properties to allow easy comparison and analysis.
I then coded in my WinForm a way to capture the user’s mouse strokes and putting them into this signature graph. First, I started with some form level variables:
Boolean IsCapturing = false;
private Point startPoint;
private Point endPoint;
Pen pen = new Pen(Color.Black);
Glyph glyph = null;
Signature signature = new Signature();
String fileName = @"signature.xml";
I then handled three events from the panel:
private void SignaturePanel_MouseMove(object sender, MouseEventArgs e)
{
if (IsCapturing)
{
if (startPoint.IsEmpty && endPoint.IsEmpty)
{
endPoint = e.Location;
}
else
{
startPoint = endPoint;
endPoint = e.Location;
Line line = new Line(startPoint, endPoint);
glyph.Lines.Add(line);
DrawLine(line);
}
}
}
private void SignaturePanel_MouseUp(object sender, MouseEventArgs e)
{
IsCapturing = false;
signature.Glyphs.Add(glyph);
startPoint = new Point();
endPoint = new Point();
}
private void SignaturePanel_MouseDown(object sender, MouseEventArgs e)
{
IsCapturing = true;
glyph = new Glyph();
}
Basically, every time a user clicks down it starts capturing the points and turning them into lines. When the user clicks up, all of those lines go into 1 glyph. Capture…Rinse….Repeat.
There is 1 supporting function (DrawLine) that looks like this to render it to the screen:
private void DrawLine(Line line)
{
using (Graphics graphic = this.SignaturePanel.CreateGraphics())
{
graphic.DrawLine(pen, line.StartPoint, line.EndPoint);
}
}
A couple of notes on the code blocks above.
- The Point struct has a convenience property called IsEmpty. This resolves to X and Y equaling 0.
- The Point Equals overload resolved to the X and Y values. If you have 2 instances of a Point with the same X and Y, they are equal.
Once the signature is captured on the panel, I needed a way to save the signature. Most people capture the image. Me, I want the signature transformed into structured data for better down-steam analysis. Therefore, I decided to put it into XML. To that end, I marked all of the classes in the Signature graph as Serializable. I then created two functions to push and pull the signature out of a XML file:
private void SerializeSignature()
{
XmlSerializer serializer = new XmlSerializer(typeof(Signature));
if (File.Exists(fileName))
{
File.Delete(fileName);
}
using (TextWriter textWriter = new StreamWriter(fileName))
{
serializer.Serialize(textWriter, signature);
textWriter.Close();
}
}
And
private void DeserializeSignature()
{
XmlSerializer deserializer = new XmlSerializer(typeof(Signature));
using (TextReader textReader = new StreamReader(fileName))
{
signature = (Signature)deserializer.Deserialize(textReader);
textReader.Close();
}
}
I then wired up the button clicks to save the signature:
private void ExportButton_Click(object sender, EventArgs e)
{
SerializeSignature();
}
and to load it:
private void ImportButton_Click(object sender, EventArgs e)
{
DeserializeSignature();
ClearSignaturePanel();
DrawSignature();
}
and these are the two other supporting methods:
private void ClearSignaturePanel()
{
using (Graphics graphic = this.SignaturePanel.CreateGraphics())
{
SolidBrush solidBrush = new SolidBrush(Color.LightBlue);
graphic.FillRectangle(solidBrush, 0, 0, SignaturePanel.Width, SignaturePanel.Height);
}
}
and
private void DrawSignature()
{
foreach (Glyph glyph in signature.Glyphs)
{
foreach (Line line in glyph.Lines)
{
DrawLine(line);
}
}
}
Sure enough, here is the XML in the file:

The problem is that this file is larger than a image file – but much more analyzable (and yes, that is a real word). I then wanted to display the signature in a web browser. To that end, I fired up a classic ASP.NET application and created a web control. In the code, I rendered the points out of the XML file back into a graphic:
protected void Page_Load(object sender, EventArgs e)
{
this.Response.ContentType = "image/gif";
using (Bitmap bitmap = new Bitmap(200, 100))
{
using (Graphics graphics = Graphics.FromImage(bitmap))
{
SignatureFactory signatureFactory = new SignatureFactory();
String fileName = @"C:\signature.xml";
Signature signature = signatureFactory.LoadSignatureFromFileSystem(fileName);
Pen pen = new Pen(Color.Red);
foreach (Glyph glyph in signature.Glyphs)
{
foreach (Line line in glyph.Lines)
{
graphics.DrawLine(pen, line.StartPoint.X, line.StartPoint.Y,
line.EndPoint.X, line.EndPoint.Y);
}
}
bitmap.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Gif);
}
}
}
And the output on a web form:
