Generating signatures

Published on by Yousfi Benameur


How to generate programmatly a user signature ?
must present a support as a form to draw manually the user signature and save it as image format.
can integrate it in a field table or put it simply in a folder and call it when needed.

i present 3 solutions to do that
-a pure vfp solution with native and extended gdiplusX
-a mixed code vfp+pure javascript solution
-using a cool com microsoft object shipped with win8.1 and win10 (this last for sure).
-i hope soon  publishing a pure vfp solution with APIs only.




this code produces a signature as image.
it uses a toolbar class with some utilities.
*draw signature with vfp native functions
*can clear drawing or make eraser to clear some drawing portion (can choose its width).
*can use  pen (with drawWidth property) and choose its color.
*uses gdiplusX to capture drawing as png image and resize it as wanted (width x height)
*can view  image produced
*system.app of gdiplusX library must be in source folder in preference.


Click on code to select [then copy] -click outside to deselect


*1*
Publi yform
yform=Newobject("ysignature")
yform.Show
Read Events
Retu
*
Define Class ysignature As Form
    Height = 480
	Width = 680
	ShowTips=.T.
	ShowWindow = 2
	AutoCenter = .T.
	Caption = "Enter Your Signature Below"
	FillStyle = 0
	Icon = ""
	BackColor = Rgb(255,255,255)
	otoolbar = .F.

	Name = "Form1"

	Procedure capture
	Local  lcdest
	m.lcdest=m.yrep+"ysignature.png"

	Local loBMP As xfcbitmap
	Thisform.otoolbar.Hide()
	sleep(20)
	With _Screen.System.drawing
		loBMP = .Bitmap.fromscreen(_Screen.ActiveForm.HWnd,0+Sysmetric(3),0+Sysmetric(9)+Sysmetric(4),Thisform.Width,Thisform.Height)
		Local lnWidth, lnHeight
		lnWidth=Thisform.otoolbar.text1.Value
		lnHeight=Thisform.otoolbar.text2.Value

		If lnWidth=0
			lnWidth=120
		Endi

		If lnHeight=0
			lnHeight=60
		Endi
******
* Create a New Image with the desired size
		Local loResized As xfcbitmap
		loResized = .Bitmap.New(lnWidth, lnHeight,.Imaging.PixelFormat.Format32bppARGB)

* Set the image resolution to be the same as the original
		loResized.SetResolution(loBMP.HorizontalResolution,loBMP.VerticalResolution)

* Obtain a Graphics object to get the rights to draw on it
		Local loGfx As xfcGraphics
		loGfx = .Graphics.FromImage(loResized)

* Set some properties, to ensure to have a better quality of image
		loGfx.SmoothingMode = .Drawing2D.SmoothingMode.HighQuality
		loGfx.InterpolationMode = .Drawing2D.InterpolationMode.HighQualityBicubic

* Draw the source image on the new image at the desired dimensions
		loGfx.DrawImage(loBMP, 0, 0, lnWidth, lnHeight)

* Save the resized image as Png
		loResized.Save(m.lcdest, .Imaging.ImageFormat.Png)

	Endwith
	Thisform.otoolbar.Show()
	Messagebox(m.lcdest+" captured !",0+32+4096,'',1200)
	Endproc

	Procedure Init
	Do Locfile('system.app')   &&put system.app in source folder

	Declare Integer Sleep In kernel32 Integer
	Publi m.yrep
	m.yrep=Addbs(Justpath(Sys(16,1)))

	With Thisform
		.ScaleMode		= 3
		.MousePointer	= 2
		.DrawMode       = 13
		.DrawWidth		= 3

	Endwith
	Endproc

	Procedure MouseMove
	Lparameters nButton, nShift, nXCoord, nYCoord
	If nButton = 1 And This.MousePointer = 2
		Thisform.Line(nXCoord, nYCoord)
	Endif
	Endproc

	Procedure MouseDown
	Lparameters nButton, nShift, nXCoord, nYCoord
	If Thisform.MousePointer = 2
		Thisform.PSet(nXCoord, nYCoord)
	Endif
	Endproc

	Procedure Activate
	If Type("thisform.oToolbar")="O" And;
			!Isnull(Thisform.otoolbar)
		Return
	Endif

	Thisform.otoolbar=Create("ysign",Thisform)
	Thisform.otoolbar.Dock(0)
	Thisform.otoolbar.Show
	Thisform.MouseDown(Thisform.Width/2,Thisform.Height/2)
	Endproc

	Procedure Destroy
	Clea Events
	Endproc

Enddefine
*
*-- EndDefine: ysignature

*
Define Class ysign As Toolbar
	Caption = "Toolbar1"
	Height = 42
	Left = 0
	Top = 0
	Width = 528
	ShowWindow = 1
	oformref = .F.
	Name = "aa"

	Add Object separator13 As Separator With ;
		Top = 3, ;
		Left = 5, ;
		Height = 0, ;
		Width = 0, ;
		Name = "Separator13"

	Add Object separator12 As Separator With ;
		Top = 3, ;
		Left = 13, ;
		Height = 0, ;
		Width = 0, ;
		Name = "Separator12"

	Add Object label1 As Label With ;
	    autosize=.t.,;
		FontBold = .T., ;
		FontSize = 12, ;
		ForeColor = Rgb(255,255,255), ;
		BackColor = Rgb(0,0,128), ;
		Caption = "Pen", ;
		Height = 24, ;
		Left = 13, ;
		Top = 3, ;
		Width = 36, ;
		Name = "Label1"

	Add Object separator11 As Separator With ;
		Top = 3, ;
		Left = 56, ;
		Height = 0, ;
		Width = 0, ;
		Name = "Separator11"

	Add Object spinner2 As Spinner With ;
		FontBold = .T., ;
		Height = 24, ;
		KeyboardHighValue = 100, ;
		KeyboardLowValue = 1, ;
		Left = 56, ;
		MousePointer = 15, ;
		SpinnerHighValue = 100.00, ;
		SpinnerLowValue =   1.00, ;
		Top = 3, ;
		Width = 44, ;
		Value = 4, ;
		Name = "Spinner2"

	Add Object separator7 As Separator With ;
		Top = 3, ;
		Left = 107, ;
		Height = 0, ;
		Width = 0, ;
		Name = "Separator7"

	Add Object check1 As Checkbox With ;
	     autosize=.t.,;
		Top = 3, ;
		Left = 107, ;
		Height = 25, ;
		Width = 78, ;
		FontBold = .T., ;
		FontSize = 14, ;
		Alignment = 0, ;
		Caption = "Eraser", ;
		Value = .F., ;
		MousePointer = 15, ;
		ForeColor = Rgb(255,255,255), ;
		BackColor = Rgb(0,0,128), ;
		Name = "Check1"

	Add Object separator8 As Separator With ;
		Top = 3, ;
		Left = 192, ;
		Height = 0, ;
		Width = 0, ;
		Name = "Separator8"


	Add Object spinner1 As Spinner With ;
		FontBold = .T., ;
		Height = 24, ;
		KeyboardHighValue = 100, ;
		KeyboardLowValue = 1, ;
		Left = 192, ;
		MousePointer = 15, ;
		SpinnerHighValue = 100.00, ;
		SpinnerLowValue =   1.00, ;
		Top = 3, ;
		Width = 44, ;
		Value = 14, ;
		Name = "Spinner1"

	Add Object separator2 As Separator With ;
		Top = 3, ;
		Left = 243, ;
		Height = 0, ;
		Width = 0, ;
		Name = "Separator2"

	Add Object separator1 As Separator With ;
		Top = 3, ;
		Left = 251, ;
		Height = 0, ;
		Width = 0, ;
		Name = "Separator1"

	Add Object separator3 As Separator With ;
		Top = 3, ;
		Left = 259, ;
		Height = 0, ;
		Width = 0, ;
		Name = "Separator3"

	Add Object command2 As CommandButton With ;
		Top = 3, ;
		Left = 259, ;
		Height = 36, ;
		Width = 55, ;
		FontBold = .T., ;
		FontSize = 10, ;
		Anchor = 0, ;
		Caption = "Capture", ;
		MousePointer = 15, ;
		ForeColor = Rgb(255,255,255), ;
		BackColor = Rgb(0,128,0), ;
		Themes = .F., ;
		Name = "command2"

	Add Object separator9 As Separator With ;
		Top = 3, ;
		Left = 321, ;
		Height = 0, ;
		Width = 0, ;
		Name = "Separator9"

	Add Object command1 As CommandButton With ;
		Top = 3, ;
		Left = 321, ;
		Height = 36, ;
		Width = 72, ;
		FontBold = .T., ;
		FontSize = 10, ;
		Anchor = 8, ;
		Caption = " Clear ", ;
		TabStop = .F., ;
		ToolTipText = "Touch or Click to Clear Signature.", ;
		ForeColor = Rgb(255,255,255), ;
		BackColor = Rgb(0,0,128), ;
		Themes = .F., ;
		Name = "Command1"

	Add Object separator10 As Separator With ;
		Top = 3, ;
		Left = 400, ;
		Height = 0, ;
		Width = 0, ;
		Name = "Separator10"

	Add Object command3 As CommandButton With ;
		Top = 3, ;
		Left = 400, ;
		Height = 36, ;
		Width = 84, ;
		FontBold = .T., ;
		FontSize = 10, ;
		Anchor = 8, ;
		Caption = "Color", ;
		MousePointer = 15, ;
		ForeColor = Rgb(255,255,255), ;
		BackColor = Rgb(0,0,128), ;
		Themes = .F., ;
		Name = "Command3"

	Add Object separator4 As Separator With ;
		Top = 3, ;
		Left = 491, ;
		Height = 0, ;
		Width = 0, ;
		Name = "Separator4"

	Add Object image1 As Image With ;
		Picture = Home(1)+"graphics\icons\win95\explorer.ico", ;
		Height = 32, ;
		Left = 491, ;
		MousePointer = 15, ;
		Top = 3, ;
		Width = 32, ;
		Name = "Image1"

	Add Object separator5 As Separator With ;
		Top = 46, ;
		Left = 5, ;
		Height = 0, ;
		Width = 0, ;
		Name = "Separator5"

	Add Object txt1 As TextBox With ;
		top=56 , ;
		left=5 , ;
		height=27 , ;
		width=40, ;
		value=120 , ;
		tooltiptext="Image Width",;
		Name="text1"

	Add Object separator5_ As Separator With ;
		Top = 46, ;
		Left = 5, ;
		Height = 0, ;
		Width = 0, ;
		Name = "Separator5_"

	Add Object txt1 As TextBox With ;
		top=56 , ;
		left=5 , ;
		height=27 , ;
		width=40, ;
		value=60 , ;
		tooltiptext="Image Height",;
		Name="text2"


	Add Object separator6 As Separator With ;
		Top = 46, ;
		Left = 5, ;
		Height = 0, ;
		Width = 0, ;
		Name = "Separator6"

	Add Object separator71 As Separator With ;
		Top = 46, ;
		Left = 5, ;
		Height = 0, ;
		Width = 0, ;
		Name = "Separator71"

	Add Object yhelp As Label With ;
		FontBold = .T., ;
		FontSize = 16, ;
		Caption = "?", ;
		Height = 24, ;
		Left = 13, ;
		Top = 3, ;
		Width = 36, ;
		ForeColor = Rgb(0,0,255), ;
		mousepointer=15 , ;
		Name = "yHelp"


	Procedure Init
	#Define ERR_NOFORMPARM_LOC	"You must pass a form reference to create this toolbar."
	Parameter oForm
	If Type("m.oForm")#"O" Or Isnull(m.oForm) Or Upper(oForm.BaseClass) # "FORM"
		Messagebox(ERR_NOFORMPARM_LOC)
		Return .F.
	Endif
	This.oformref = oForm
	Endproc

	Procedure spinner2.InteractiveChange
	_Screen.ActiveForm.DrawWidth = This.Value
	Endproc

	Procedure check1.Click
	With  _Screen.ActiveForm

		If This.Value
			.DrawWidth = This.Parent.spinner1.Value
			.ForeColor=.BackColor
		Else
			.DrawWidth =This.Parent.spinner2.Value

			.DrawMode = 13
		Endif

	Endwith
	Endproc

	Procedure spinner1.InteractiveChange
	If This.Parent.check1.Value
		_Screen.ActiveForm.DrawWidth = This.Value
	Endif
	Endproc

	Procedure command2.Click

	_Screen.ActiveForm.capture()
	Endproc

	Procedure command1.Click
	_Screen.ActiveForm.Cls
	This.Parent.check1.Value=.F.
	Endproc

	Procedure command3.Click
	Local m.xcolor
	m.xcolor=Getcolor()
	If m.xcolor=-1
		Return .F.
	Endi
	With _Screen.ActiveForm
		.ForeColor=m.xcolor
		.DrawMode=13
	Endwith
	This.Parent.check1.Value=.F.
	Endproc

	Procedure image1.Init
	This.Picture=Home(1)+"graphics\icons\win95\explorer.ico"
	Endproc

	Procedure image1.Click
	Local m.oo
	m.oo=m.yrep+"ysignature.png"

	If File(m.oo)
		Run/N explorer &oo
	Endi
	Endproc

	Procedure yhelp.Click
	local m.myvar
	text to m.myvar noshow
	this produces a signature as image
*draw signature with vfp native functions
*can clear drawing or make eraser to clear some drawing portion (can choose its width).
*can build pen (with drawWidth) and choose its color.
*uses gdiplusX to capture drawing as png image and resize it as wanted (width x height)
*can view  image produced
*system.app of gdiplusX library must be in source folder in preference.


	endtext
	Messagebox(m.myvar,0+32+4096,"ysignature application")
	Endproc


Enddefine
*
*-- EndDefine: ysign




see also in same registry the link below .
see also in same registry the link below .

see also in same registry the link below .

Click on code to select [then copy] -click outside to deselect


*2* a web signature with html5 canvas

*this builds an html5 canvas on a form(IE11 recquired-vfp browser emulation as IE11 recquired)
*choose a pencil color and draw signature.can erase drawing(see button "eraser")
*can clear the drawing with eraser button and mousedown...
*can save signature as PNG imlage on disc (rightclick on and choose a destination png file on disc)
*original javascript source from Web (http://stackoverflow.com/questions/2368784/draw-on-html5-canvas-using-a-mouse)

Publi yform
yform=Newobject("ysign")
yform.Show
Read Events
Retu
*
Define Class ysign As Form
    BorderStyle = 0
	Height = 440
	Width = 850
	ShowWindow = 2
	MaxButton=.F.
	AutoCenter = .T.
	Caption = "Canvas Signature-save as PNG..."
	Name = "Form1"

	Add Object olecontrol1 As OleControl With ;
		oleclass="Shell.explorer.2",;
		Top = -24, ;
		Left = -84, ;
		Height = 469, ;
		Width = 960, ;
		Name = "Olecontrol1"

	Procedure Destroy
	Erase Addbs(Sys(2023))+"temp.html"    &&clean
	Clea Events
	Endproc

	Procedure Init
	Set Safe Off
	Endproc

	Procedure olecontrol1.Init
	Local m.myvar
	TEXT to m.myvar noshow
		<html>
		<meta http-equiv="X-UA-Compatible" content="IE=11" >
		<script type="text/javascript">
		var canvas, ctx, flag = false,
		    prevX = 0,
		    currX = 0,
		    prevY = 0,
		    currY = 0,
		    dot_flag = false;

		var x = "black",
		    y = 2;

		function init() {
		    canvas = document.getElementById('can');
		    ctx = canvas.getContext("2d");
		    w = canvas.width;
		    h = canvas.height;

		    canvas.addEventListener("mousemove", function (e) {
		        findxy('move', e)
		    }, false);
		    canvas.addEventListener("mousedown", function (e) {
		        findxy('down', e)
		    }, false);
		    canvas.addEventListener("mouseup", function (e) {
		        findxy('up', e)
		    }, false);
		    canvas.addEventListener("mouseout", function (e) {
		        findxy('out', e)
		    }, false);
		}

		function color(obj) {
		    switch (obj.id) {
		        case "green":
		            x = "green";
		            break;
		        case "blue":
		            x = "blue";
		            break;
		        case "red":
		            x = "red";
		            break;
		        case "yellow":
		            x = "yellow";
		            break;
		        case "orange":
		            x = "orange";
		            break;
		        case "black":
		            x = "black";
		            break;
		        case "white":
		            x = "white";
		            break;
		    }
		    if (x == "white") y = 14;
		    else y = 2;

		}

		function draw() {
		    ctx.beginPath();
		    ctx.moveTo(prevX, prevY);
		    ctx.lineTo(currX, currY);
		    ctx.strokeStyle = x;
		    ctx.lineWidth = y;
		    ctx.stroke();
		    ctx.closePath();
		}

		function erase() {
		    var m = confirm("Want to clear");
		    if (m) {
		        ctx.clearRect(0, 0, w, h);
		        document.getElementById("canvasimg").style.display = "none";
		    }
		}

		function save() {
		    document.getElementById("canvasimg").style.border = "2px solid";
		    var dataURL = canvas.toDataURL();
		    document.getElementById("canvasimg").src = dataURL;
		    document.getElementById("canvasimg").style.display = "inline";
		    alert("Rightclick and saves as PNG....");
		}

		function findxy(res, e) {
		    if (res == 'down') {
		        prevX = currX;
		        prevY = currY;
		        currX = e.clientX - canvas.offsetLeft;
		        currY = e.clientY - canvas.offsetTop;

		        flag = true;
		        dot_flag = true;
		        if (dot_flag) {
		            ctx.beginPath();
		            ctx.fillStyle = x;
		            ctx.fillRect(currX, currY, 2, 2);
		            ctx.closePath();
		            dot_flag = false;
		        }
		    }
		    if (res == 'up' || res == "out") {
		        flag = false;
		    }
		    if (res == 'move') {
		        if (flag) {
		            prevX = currX;
		            prevY = currY;
		            currX = e.clientX - canvas.offsetLeft;
		            currY = e.clientY - canvas.offsetTop;
		            draw();
		        }
		    }
		}
		</script>
		<body onload="init()";>
		    <canvas id="can" width="400" height="400" style="position:absolute;top:10%;left:10%;border:2px solid;cursor:pointer;"></canvas>
		    <div style="position:absolute;top:12%;left:40%;">Choose Color</div>
		    <div style="position:absolute;top:17%;left:45%;width:10px;height:10px;background:green;" id="green" onclick="color(this)"></div>
		    <div style="position:absolute;top:17%;left:46%;width:10px;height:10px;background:blue;" id="blue" onclick="color(this)"></div>
		    <div style="position:absolute;top:17%;left:47%;width:10px;height:10px;background:red;" id="red" onclick="color(this)"></div>
		    <div style="position:absolute;top:19%;left:45%;width:10px;height:10px;background:yellow;" id="yellow" onclick="color(this)"></div>
		    <div style="position:absolute;top:19%;left:46%;width:10px;height:10px;background:orange;" id="orange" onclick="color(this)"></div>
		    <div style="position:absolute;top:19%;left:47%;width:10px;height:10px;background:black;" id="black" onclick="color(this)"></div>

		    <div style="position:absolute;top:22%;left:43%;">Eraser</div>
		    <div style="position:absolute;top:22%;left:48%;width:15px;height:15px;background:white;border:2px solid;" id="white" onclick="color(this)"></div>
		    <img id="canvasimg" style="position:absolute;top:10%;left:52%;" style="display:none;">
		    <input type="button" value="save" id="btn" size="30" onclick="save()" style="position:absolute;top:88%;left:12%;">
		    <input type="button" value="clear" id="clr" size="23" onclick="erase()" style="position:absolute;top:88%;left:18%;">
		</body>
		</html>
	ENDTEXT
	Local m.ldest
	m.lcdest=Addbs(Sys(2023))+"temp.html"
	Strtofile(m.myvar,m.lcdest)
	This.silent=.T.
	This.Navigate(m.lcdest)
	Endproc

Enddefine
*
*-- EndDefine: ysign



see in my blog  html5 canvas sources similar examples.

see in my blog html5 canvas sources similar examples.

Click on code to select [then copy] -click outside to deselect

                     


*3* updated on 12 september 2016
* this refers to windows10 inkObjCore.dll to create a com  object who is a surface for drawing
*maybe its also available on win8 and win8.1 (to confirm)
*maybe this dll is an update of lnObj.dll of old version (to confirm).
*this code creates a new object using the InkCollector class.
*Attach the InkCollector to a form using the form's window handles.
*Activate the InkCollector by setting its Enabled property to true (.T.)
*Run the following code and start inking!
*Note that the object created dont can be embed directly as an activeX on the form (result error if the case).
*the result drawing can be saved as gif on the disc when rleasing the form.
*it can be used as a quick signature tool.
*refrence:https://msdn.microsoft.com/en-us/library/ms965060.aspx
*with this article can build many configurations
* with this drawing COM object.
*this code can be available on any Microsoft Tablet PC Platform SDK

Local yform As Form
yform = Newobject("ydraw")
*-- Create a new InkCollector, and set the
*-- window handle to be the form on which
Publi oInkCollector As  MSINKAUT.inkcollector.1
*-- we want to work with the InkCollector
oInkCollector =Newobject("msinkaut.inkcollector.1")
oInkCollector.HWnd = yform.HWnd

*can use another properties marginX,marginY,...


With oInkCollector.defaultDrawingAttributes
    .Color=255  &&can set any pen color (getcolor())
	.Width=150   && set a pen width in activeX scale
	.penTip=0   &&ball   (1=rectangle)
	.antiAliased=.T.
	.fitToCurve=.F.
Endwith

*-- That's it, we're done setting it up. Enable
*-- the InkCollector so we can start using it.
oInkCollector.Enabled = .T.


*set the drawing area object on the form (otherwise all the form surface is the drawing area by default)
Local oInkRectangle As MSINKAUT.inkrectangle
* Create an inkrectangle object
oInkRectangle = Newobject("msinkaut.inkrectangle")

* set the drawing area.
With oInkRectangle
	.Top = yform.shape1.Top
	.Left =yform.shape1.Left
	.Right =.Left+yform.shape1.Width
	.Bottom =.Top+yform.shape1.Height
Endwith
* here we set the rectangle of drawing area
oInkCollector.SetWindowInputRectangle(oInkRectangle)

*-- InkCollector is turned on, show the form
yform.Show(1)  &&modal

Return


*form class
Define Class ydraw As Form
	ShowWindow=0
	Desktop=.T.
	AutoCenter=.T.
	Caption="Draw in the shape area"
	Add Object shape1 As Shape With ;
		width=200,;
		height=200,;
		top=20,;
		left=20,;
		name="shape1"

	Procedure Init
	With Thisform.shape1
		.Left=20
		.Top=20
		.Width=.Parent.Width-2*20
		.Height=.Parent.Height-2*20
		.BackColor=Rgb(255,255,210)
	Endwith

*Can create buttons to save as image (save(2) method), clear canvas,choose penwidth,pencolor....
*this code below asks to save as gif the drawing(it represents the adjustable area drawn on the form)
	Procedure QueryUnload
	lsInk=oInkCollector.Ink.Save(2)   &&save as gif file
	Strtofile(lsInk, Getfile("gif"))
	Endproc

	Procedure Destroy
	oInkCollector=Null
	Release oInkCollector
	Endproc
Enddefine
*Enddefine Yform


Click on code to select [then copy] -click outside to deselect


to test if the com msinkaut objects are installed on your machine or Tablet  for the code above, you can insert  these codes:

*inkCollector object
Try
    oInkEdit = Newobject("msinkaut.inkcollector.1")
Catch
   messagebox( "msinkaut.inkcollector.1 control is not installed!",0+32+4096)
Endtry

*inkRectangle  object
Try
    oInkEdit = Newobject("msinkaut.inkrectangle")
Catch
   messagebox( "msinkaut.inkrectangle control is not installed!",0+32+4096)
Endtry



this drawing is saved as any pointed gif on disc when releasing the form.discarding dont save anything.

this drawing is saved as any pointed gif on disc when releasing the form.discarding dont save anything.

Important:All Codes above are tested on VFP9SP2 & windows 10 pro and IE. emulation.

Generating signatures
To be informed of the latest articles, subscribe:
Comment on this post
C
Very beautiful Yousfi!!!
Reply