This is a great solution created by Richard Wixom, whom I’ve worked with over the years. Richard is the president and owner of DNSalePrice.com. He spends a lot of his time buried in algorithms deciphering the goings on in the domain name industry and creating huge databases with information about domain names. We collaboratively worked on this solution and thought it was an interesting exercise that others might appreciate.
TOPAZ Signature Pads can be enabled for InfoPath 2007 with the signature image then stored and embedded within the InfoPath form. The following approach uses C#/.Net managed code with the code and appropriate DLL’s embedded within published InfoPath forms. Standard InfoPath features such as email distribution, SharePoint storage, etc. are available for InfoPath client. Web-enabled InfoPath forms are not supported.
Prerequisites for enabling TOPAZ Signature Pads with InfoPath 2007:
1. TOPAZ signature pad hardware and software installed.
2. Security level for InfoPath form set to Full Trust and signed.
3. Programming language for InfoPath form set to “C#”
4. Compatibility for InfoPath form and “Design form template that can be opened in browser” is not set.
5. Local access to the C# SigPlusNET assembly. This can be found in the Topaz’s “SigPlusNETDemoCSharp” download that is available here.
Setup requires three steps:
1. Adding the required controls to InfoPath form
2. Adding DLL reference to code
3. Adding required code
Estimated time to complete should be under five minutes.
Add Required Controls
In “Design” mode, create a new InfoPath form and verify/set settings as stated in “Prerequisites.” Add two Buttons, a Text Box and a Picture control to the form. Use a layout similar to the following:
Set the control properties on the first button (Label and ID) as shown below. Both C# and XML are case-sensitive languages so be sure to use the same letter case as shown.
Set the control properties for the second button as shown below:
For the Text Box properties, under Data tab, set Field name as shown below:
For the Text Box properties, Display tab, check “Read-only” as shown below:
For the Text Box properties, Size tab, set size values as shown below:
For the Picture properties, under the Data tab, enter Field name as shown below and uncheck the box to “Allow the user to browse, delete, and replace pictures.”
Under Tools/Programming, open Microsoft Visual Studio Tools for Applications. In the Project Explorer (see tabs on right), right-click on “Reference”, select “Add Reference” and add the following two references:
1. Under the .Net tab, locate and add “System.Drawing”.
2. Under the Browse tab, navigate the full path to SigPlusNETDemoCSharp (see Prerequisites) and add “SigPlus.dll”.
Project Explorer should now look like the following (see highlighted reference):
Now cut and paste the following replacement code over the default code — EXCEPT you will need to preserve the default namespace that is provided. The following is an example of the default namespace that you’ll need to preserve when pasting the replacement code.
Replacement code:
using Microsoft.Office.InfoPath;
using System;
using System.Windows.Forms;
using System.Xml;
using System.Xml.XPath;
using mshtml;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
namespace _0900_A_with_Signature ç [retain the default value here]
{
public partial class FormCode
{
internal Topaz.SigPlusNET SigPlus = new Topaz.SigPlusNET();
// NOTE: The following procedure is required by Microsoft Office InfoPath.
// It can be modified using Microsoft Office InfoPath.
public void InternalStartup()
{
((ButtonEvent)EventManager.ControlEvents["Button_Sign"]).Clicked += new ClickedEventHandler(Button_Sign_Clicked);
((ButtonEvent)EventManager.ControlEvents["Button_Done"]).Clicked += new ClickedEventHandler(Button_Done_Clicked);
}
public void Button_Sign_Clicked(object sender, ClickedEventArgs e)
{
SetSignatureImage(String.Empty);
SetTopazMessage("Sign on signature pad and then click \"Done\".");
SigPlus.SetTabletState(1); //tablet on
SigPlus.ClearTablet();
}
public void Button_Done_Clicked(object sender, ClickedEventArgs e)
{
SigPlus.SetTabletState(0); //tablet off
SigPlus.SetImageXSize(400);
SigPlus.SetImageYSize(100);
SigPlus.SetImagePenWidth(11);
SigPlus.SetJustifyMode(5);
Image sigImage = SigPlus.GetSigImage();
String sigBase64 = ImageToBase64(sigImage, ImageFormat.Jpeg);
//verify signature entered and read
if (sigBase64.Length > 2000)
{
SetSignatureImage(sigBase64);
SetTopazMessage(string.Empty);
}
else { SetTopazMessage("Signature not recoginized. Please verify signature pad, then click \"Sign\" button and follow instructions."); }
}
public void SetTopazMessage(string message)
{
string XpathForTopazMessage = "/my:Fields/my:TopazMessage";
XPathNavigator messageField = this.MainDataSource.CreateNavigator().SelectSingleNode(XpathForTopazMessage, NamespaceManager);
messageField.SetValue(message);
}
public void SetSignatureImage(string base64Image)
{
string XpathForSignatureImage = "/my:Fields/my:SignatureImage";
XPathNavigator imageField = this.MainDataSource.CreateNavigator().SelectSingleNode(XpathForSignatureImage, NamespaceManager);
DeleteNil(imageField); //remove xsi:nil attribute
imageField.SetValue(base64Image);
}
public string ImageToBase64(Image image, ImageFormat format)
{
using (MemoryStream ms = new MemoryStream())
{
// Convert Image to byte[]
image.Save(ms, format);
byte[] imageBytes = ms.ToArray();
// Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes);
return base64String;
}
}
public void DeleteNil(XPathNavigator node)
{
if (node.MoveToAttribute("nil","http://www.w3.org/2001/XMLSchema-instance"))
{
node.DeleteSelf();
}
}
}
}
Click on “Build” and verify that your template builds without programming errors. If you encounter any errors, correct as required. The most common error will be incorrect entry of control ids as noted above.
Save your source files, close Visual Studio for Applications, add required content and controls to your InfoPath form and publish.
I have done everything as stated on the blog, I am getting this error. The link is a screen shot. I am awful when it comes to the C# stuff. Thanks for your help.
Thanks,
Shawn
I have followed the instructions for using a Topaz Signature Pad with InfoPath to the T and it isn’t working. I get the following errors:
An unhandled exception has occurred in the form’s code.
System.NullReferenceException
Object reference not set to an instance of an object.
at _0900_A_with_Signature.FormCode.DeleteNil(XPathNavigator node)
at _0900_A_with_Signature.FormCode.SetSignatureImage(String base64Image)
at _0900_A_with_Signature.FormCode.Button_Sign_Clicked(Object sender, ClickedEventArgs e)
at Microsoft.Office.InfoPath.Internal.ButtonEventHost.OnButtonClick(DocActionEvent pEvent)
at Microsoft.Office.Interop.InfoPath.SemiTrust._ButtonEventSink_SinkHelper.OnClick(DocActionEvent pEvent)
Any ideas on what I am doing wrong? any help would be greatly appreciated.
Of course, one of the things that happens when you post code that is not fully debugged is that you get, well, uh…bugs. Try something like this in SetSignatureImage.
internal void SetSignatureImage(string base64Image, ClickedEventArgs e)
{
try
{
XPathNavigator imageField = GetNavigator(baseSignatureImage, e);
DeleteNil(imageField); //remove xsi:nil attribute
imageField.SetValue(base64Image);
}
catch
{
UnexpectedError();
}
}
I was also receiving the same error message as Julie Ziriax and replaced SetSignatureImage with what you provided, but it is still giving me errors while building.
No overload for method ‘SetSignatureImage’ takes ‘1’ arguments (occurs twice)
The name ‘GetNavigator’ does not exist in the current context
The name ‘baseSignatureImage’ does not exist in the current context
The name ‘UnexpectedError’ does not exist in the current context
After trying on my own for a while, the best I could do was still having DeleteNil create the same error message as before.
Any help would be much appreciated
The code below works beautifully for us.
using Microsoft.Office.InfoPath;
using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using System.Xml.XPath;
using mshtml;
namespace Sign2
{
public partial class FormCode
{
Topaz.SigPlusNET SigPlusNET1;
// NOTE: The following procedure is required by Microsoft Office InfoPath.
// It can be modified using Microsoft Office InfoPath.
public void InternalStartup()
{
((ButtonEvent)EventManager.ControlEvents[“CTRL1_5”]).Clicked += new ClickedEventHandler(CTRL1_5_Clicked);
((ButtonEvent)EventManager.ControlEvents[“CTRL2_5”]).Clicked += new ClickedEventHandler(CTRL2_5_Clicked);
((ButtonEvent)EventManager.ControlEvents[“CTRL3_5”]).Clicked += new ClickedEventHandler(CTRL3_5_Clicked);
((ButtonEvent)EventManager.ControlEvents[“CTRL7_5”]).Clicked += new ClickedEventHandler(CTRL7_5_Clicked);
((ButtonEvent)EventManager.ControlEvents[“CTRL8_5”]).Clicked += new ClickedEventHandler(CTRL8_5_Clicked);
((ButtonEvent)EventManager.ControlEvents[“CTRL9_5”]).Clicked += new ClickedEventHandler(CTRL9_5_Clicked);
}
// NOTE: The following procedure is required by Microsoft Office InfoPath.
// It can be modified using Microsoft Office InfoPath.
public void CTRL1_5_Clicked(object sender, ClickedEventArgs e)
{
// Initiate the signature pad
SigPlusNET1 = new Topaz.SigPlusNET();
SigPlusNET1.SetTabletState(1);
}
public void CTRL2_5_Clicked(object sender, ClickedEventArgs e)
{
if (SigPlusNET1.NumberOfTabletPoints() > 0)
{
Image myimage = null;
SigPlusNET1.SetImageXSize(250);
SigPlusNET1.SetImageYSize(100);
SigPlusNET1.SetJustifyMode(5);
SigPlusNET1.SetImagePenWidth(7);
SigPlusNET1.SetImageFileFormat(0);
if (SigPlusNET1.NumberOfTabletPoints() > 0)
{
myimage = SigPlusNET1.GetSigImage();
}
else
{
MessageBox.Show(“Please sign the signature pad and try again”);
return;
}
/// set the form picture field to the image read from the SigPad
// get access to the picture attachment field
XPathNavigator MyPic = this.CreateNavigator().SelectSingleNode(“/my:myFields/my:Signature”, NamespaceManager);
DeleteNil(MyPic);
// this is where the real work is done. Simply take the bytes from the signature image and convert them to base64.
MyPic.SetValue(Convert.ToBase64String(imageToByteArray(myimage)));
/// cleanup
// dispose of the field
MyPic = null;
}
else
{
MessageBox.Show(“No signature captured!”);
}
}
public void CTRL3_5_Clicked(object sender, ClickedEventArgs e)
{
SigPlusNET1.ClearTablet();
// get access to the picture attachment field
XPathNavigator MyPic = this.CreateNavigator().SelectSingleNode(“/my:myFields/my:Signature”, NamespaceManager);
DeleteNil(MyPic);
// Clear the signature
MyPic.SetValue(“”);
}
public void CTRL7_5_Clicked(object sender, ClickedEventArgs e)
{
// Initiate the signature pad
SigPlusNET1 = new Topaz.SigPlusNET();
SigPlusNET1.SetTabletState(1);
}
public void CTRL8_5_Clicked(object sender, ClickedEventArgs e)
{
if (SigPlusNET1.NumberOfTabletPoints() > 0)
{
Image myimage = null;
SigPlusNET1.SetImageXSize(250);
SigPlusNET1.SetImageYSize(100);
SigPlusNET1.SetJustifyMode(5);
SigPlusNET1.SetImagePenWidth(7);
SigPlusNET1.SetImageFileFormat(0);
if (SigPlusNET1.NumberOfTabletPoints() > 0)
{
myimage = SigPlusNET1.GetSigImage();
}
else
{
MessageBox.Show(“Please sign the signature pad and try again”);
return;
}
/// set the form picture field to the image read from the SigPad
// get access to the picture attachment field
XPathNavigator MyPic = this.CreateNavigator().SelectSingleNode(“/my:myFields/my:Signature2”, NamespaceManager);
DeleteNil(MyPic);
// this is where the real work is done. Simply take the bytes from the signature image and convert them to base64.
MyPic.SetValue(Convert.ToBase64String(imageToByteArray(myimage)));
/// cleanup
// dispose of the field
MyPic = null;
}
else
{
MessageBox.Show(“No signature captured!”);
}
}
public void CTRL9_5_Clicked(object sender, ClickedEventArgs e)
{
SigPlusNET1.ClearTablet();
// get access to the picture attachment field
XPathNavigator MyPic = this.CreateNavigator().SelectSingleNode(“/my:myFields/my:Signature2”, NamespaceManager);
DeleteNil(MyPic);
// Clear the signature
MyPic.SetValue(“”);
}
public void DeleteNil(XPathNavigator node)
{
if (node.MoveToAttribute(“nil”, “http://www.w3.org/2001/XMLSchema-instance”))
node.DeleteSelf();
}
public byte[] imageToByteArray(System.Drawing.Image imageIn)
{
MemoryStream ms = new MemoryStream();
try
{
imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
}
catch
{
MessageBox.Show(“Conversion of image failed”);
}
return ms.ToArray();
}
}
}
Thanks Russell. I had to tweak the code a little to make your example work. Basically where it says
string XpathForTopazMessage = “/my:Fields/my:TopazMessage”;
AND
string XpathForSignatureImage = “/my:Fields/my:SignatureImage”;
The xpath is incorrect. In order to get the correct XPath, just get it from Infopath by right clicking on the My Fields on the right and selecting Copy XPath.
Corrected XPath
“/my:myFields/my:TopazMessage”;
“/my:myFields/my:SignatureImage”;
For a strange situation i have to replace using to Imports and the rest of the code doesn’t work i have 66 Errors, can anyone help me?
forget it i fixed
Error= Newline in constant, ) expected
if (node.MoveToAttribute(“nil”,”http://www.w3.org/2001/XMLSchema-instance"))
{
node.DeleteSelf();
}
help please
0 errors but there is a message saying “InfoPath cannot open the selected form”
missing the ;
that is a good solution, I was wondering if there is a way to also have the signature be displayed on screen as it is being drawn, maybe with ink picture? That would be helpful for people that don’t have a signature pad with LCD.
Is there a way to have the signature show on screen while drawing? This would be helpful if someone doesn’t have lcd on signature pad.
Topaz Signature Pads are very helpful for my business because I have to sign thousands of documents and checks daily. It has made my work a lot simpler.
is there any demo for web application or how can i implement topaz into web application in c#
Not aware of one. Sorry.