NAVmoble - the pocket-sized ERP
Optimized for Microsoft Dynamics NAV and Windows Mobile powered devices

Saturday, December 09, 2006

"How To" Series: Building a Signature Control in Compact Framework

It is not a rare requirement for a mobile application to provide functionality for capturing a person signature.
So, let's see if we can provide this feature into a mobile application with .NET Compact Framework.
The image bellow outlines the problem that we want to solve:



We have a mobile salesman, who collects customer orders. Our salesman should collect the customer's signatures along with the order's details. Our salesman is carrying a Pocket PC device. We should create
a software solution to allow customer's signature capturing and transmition of the signature over the wire to the office. There we have a Sql Server database to store the signatures into and signatures consuming app. , which may process the stored signatures.


We should solve the following tasks:



  1. Capturing a signature from a person from the mobile device
  2. Saving the captured signature locally on the mobile device
  3. Transmitting the saved signature over the wire and storing it on the server side
  4. Consuming the transmitted and saved signature on the server side

Let's try to solve these tasks:


Solving Task 1: Capturing a signature from a person on the mobile device


If a person should place its signature on a Pocket PC, he will probably use the stylus to write his signature on the Pocket PC screen. All we have to do is to capture the on-screen tapings and convert them into a bitmap. We will create a User Control to encapsulate this functionality. The main functionality is divided between the following UserControl event handlers:



  • OnMouseDown - here we will "remember" the coordinates of the last on-screen tapping
  • OnMouseMove - here we will draw a line from the remembered coordinates to the new(after the mouse move) on-screen mouse coordinates.


Following code example(simplified version)
...
private Bitmap SignatureImage;
private Graphics GraphicsHandle;
privte Point MouseCoords;
....
SignatureImage = new Bitmap(this.Width, this.Height);
GraphicsHandle = Graphics.FromImage(SignatureImage);
...
//remembering the coords of the last on-screen tapping into  MouseCoords member
protected override void OnMouseDown(MouseEventArgs e)
{
  base.OnMouseDown(e);
  MouseCoords.X = e.X;
  MouseCoords.Y = e.Y;
}
//draw a line from the remembered coords to the new on-screen tapping coords
protected override void OnMouseMove(MouseEventArgs e)
{
  base.OnMouseMove(e); 
  GraphicsHandle.DrawLine(SignaturePen, MouseCoords.X, MouseCoords.Y, e.X, e.Y); 
  MouseCoords.X = e.X;
  MouseCoords.Y = e.Y;

//saves the captured bitmap image into a stream
public void Save(Stream stream)
{
   SignatureImage.Save(stream, ImageFormat.Bmp);
}  


Solving Task 2: Saving the captured signature locally on the mobile device


This task is simpler. Let's pretend, we should save the captured image into a local SqlServer Mobile database.
We should have a table containing a field of type image to save the signature into it.



CRATE TABLE CUSTOMERSIGN
{


   customerNo:int not null identity
   sign:image
}


Following the code to save the captured signature:


//our signature control placed into a form
private
SignatureControl MySignatureControl;
...
string connectionString =  ...;
...
using (SqlCeConnection connection = new SqlCeConnection(connectionString))
{
  connection.Open();
  SqlCeCommand command = new SqlCeCommand("INSERT INTO CUSTOMERSIGN(sign)VALUES(?)", connection); 
 


  //getting the captured signature as stream
  MemoryStream signStream = new MemoryStream();
  MySignatureControl.Save(signStream);


  param = new SqlCeParameter("sign", SqlDbType.Binary);
  param.Value = signStream.ToArray();
  command.Parameters.Add(param);


  command.ExecuteNonQuery();
  connection.Close();
}
Now we have the signature saved locally...
We may save the signature into another storage type like a file for example.


Solving Task 3: Transmitting the saved signature over the wire


Usually the most valuable mobile applications provide functionality to send and receive data to/from some in-house systems running in the company's office.
Let's see if we can send the captured image back to the office over the wire. Although there are various communication options that may be used to transmit the signature over the wire, we will see only the Xml Web Services way in this article. Other possible options are TCP/IP transmition with sockets, Merge Replication,RDA  and why not E-mail .
First, we should create our Xml Web Service. This Xml Web Service will run on the company's office web server. The web server its self should be "http reachable" by  our PocketPC. So, when our Pocket PC device gets a network connection, it may invoke our Xml Web Service and send all the captured signs back to the office.
Let's have a similar table (CUSTOMERSIGN) created into a Sql Server, which also runs in our office. Our Xml Web Service will receive the captured signatures from the mobile app. and will save them into the CUSTOMERSIGN table in the Sql Server. Later another app. may fetch the stored signs to process them in some way.


The  Xml Web Service will have one web method like this:




[WebMethod]
public void TransmitSignature(int customerId, byte[]
signature)
{
  using(SqlConnection connection = new SqlConnection(connectionString))
  {
     SqlCommand insertCmd = new SqlCommand("INSERT INTO CUSTOMERSIGN(customerId,sign)VALUES(@customerId,@signature)", connection); 
     insertCmd.Parameters.AddWithValue("@customerId", customerId); 
     insertCmd.Parameters.AddWithValue("@signature",signature);
     insertCmd.ExecuteNonQuery();
  }


}


Then on the mobile side, we may create a web reference to our Web service and consume it, when a network connection is available


OfficeService.SignService signService = new OfficeService.SignService();
using(SqlCeConnection cnn = new SqlCeConnection(connectionString))
{      


        SqlCeCommand cmd = new SqlCeCommand("SELECT customerId,signature FROM CUSTOMERSIGN",cnn);
        SqlCeDataReader reader  =  cmd.ExecuteReader();
        while(reader.Read())
        {
            int customerId= (int)reader[0];


            //read the signature from the mobile database
            int imgSize = reader.GetBytes(1,0,null,0,0); 
            byte[] signImageData = new byte[imgSize];
            reader.GetBytes(1,0,signImageData,0,0); 


            //transmit signature over the wire
            signService.TransmitSignature(customerId,signImageData);
         }          


         //delete transmited signatures from the mobile database
         
SqCeCommand deleteCmd = new SqCeCommand("DELETE FROM CUSTOMERSIGN",cnn);
         deleteCmd.ExecuteNonQuery();
 } 


Note, that this example is not quite efficient from a performance point of view. It will be more performant to have a Web Method, which accepts
a collection of signatures at a time. It may be performed easily by using DataSet to fetch and  transfer the captured signatures:

[WebMethod]
public void
TransmitSignature(DataSet signatures
)

Solving Task 4: Visualizing the transmited signature on the server side


Once we have the captured signatures saved on the server side, we may need to consume them. For example we may want to show them as images on the screen.
In order to do this we should fetch them from the database:



//picturebox control to show the signature
private PictureBox pictureBox1;
...
int interestingCusotmerId;
 ...
SqlCommand cmd = new SqlCommand("SELECT signature FROM CUSTOMERSIGN WHERE customerId=@customerId", connection);
cmd.Parameters.AddWithValue("@customerId",interestingCusotmerId);
SqlDataReader reader  =  cmd.ExecuteReader();
if(reader.Read())
{
    //read the signature from the database
    int imgSize = reader.GetBytes(0,0,null,0,0); 
    byte[] signImageData = new byte[imgSize];
    reader.GetBytes(0,0,signImageData,0,0);
    //show the signature as Bitmap image
    using(MemoryStream ms = new MemoryStream(signImageData))
    {
      pictureBox1.Image = new Bitmap(ms);
    }
}          


The presented example is not a complete solution. It just outlines some of the common problems, which should be addressed if one needs to build a signature capturing solution. 
A real world solution may be far more complicated and should address a lot of problems not mentioned here. For example there are other signature capturing techniques ,which may store the signature in more compressed format. One may need to encrypt/decrypt the captured signature to protect it or validate the signature(biometric). Please see the links bellow for more examples.



Links:


2 comments:

anjelika said...

Very nice implementation.
Just a quick question..is there a way to check if the user has actually signed or not?
It would be helpful for validation purposes.
Thanks

iPhone Signature Capture said...

Hi for validation of an iPhone signature control you can check www.supersignature.com it allows to capture signature over browsers from mobile devices like iPhone, iPad, Android and all major PC browsers.