Signature Capture

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:

image

 

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:

image

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:

image

2 Responses to Signature Capture

  1. hello sir,

    this code is more efficient for window application ,but i want to do this in web application ,then how can i done this feature website ,please provide some solution …

    and also describe SignatureFactory directory or library ,how can i add this library and from ..
    please revert back soon…

    thanks

  2. sukitspanos says:

    THANK YOU! I have been messing around for hours trying to get a signature capture in a windows form to work.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: