C#结合JavaScript实现手写板签名效果
作者:初九之潜龙勿用
应用场景
我们最近开发了一款笔迹测试功能的程序(测试版),用户在手写板上手写签名,提交后即可测试出被测试者的心理素质评价分析。类似功能的场景还比如,在银行柜台 办理业务,期间可能需要您使用手写设备进行签名并确认;保险续期小程序,到期后需要你在确认续期条款后,在手机上提供的签名区域进行签名并提交确认。
实现效果
笔迹测试显示界面如下:
可选择画笔颜色(默认为黑色笔) ,在虚线框内可随便写一段文字,点击提交即可。当然程序还提供拍照上传功能,这里不再详述。下面我们开始介绍,C#如何结合JavaScript实现手写板写字并上传到服务器进行处理。
开发运行环境
操作系统: Windows Server 2019 DataCenter
手写触屏设备:Microsoft Surface Pro 9
.net版本: .netFramework4.0 或以上
开发工具:VS2019 C#
设计实现
手写功能
设计采用了 iframe 嵌入式的方式实现 JavaScript 前端,假设页面为 hw.aspx ,该页面实现了手写功能、重写功能、画笔选择功能和提交功能,其完整示例代码如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=yes"/> <title>手写板</title> <style type="text/css"> html,body{ margin: 0; padding: 0; } .saveimg{ text-align: center; } .saveimgs span{ display: inline-block; margin-top:5px; } </style> </head> <body> <script src="jquery-3.3.1.min.js"></script> <div align="center"> <canvas id="myCanvas" width="500" height="300" style="border:1px dotted #6699cc"></canvas> <div class="control-ops control"> <button type="button" class="btn btn-primary" onclick="javascript:clearArea();return false;">重写</button> <select style="display:none" id="selWidth" onchange="aaa()"> <option value="1">1</option> <option value="3" selected="selected">3</option> <option value="5">5</option> <option value="7">7</option> <option value="9">9</option> <option value="11">11</option> </select> <select id="selColor" onchange="aaa2()"> <option value="black" selected="selected">黑色笔</option> <option value="blue">蓝色笔</option> <option value="red">红色笔</option> <option value="green">绿色笔</option> <option value="yellow">黄色笔</option> <option value="gray">深灰笔</option> </select> <button type="button" class="saveimg" onclick="javascript:saveImageInfo();return false;">提交</button> </div> <div class="saveimgs"></div> </div> </body> <script type="text/javascript"> var mousePressed = false; var lastX, lastY; var ctx = document.getElementById('myCanvas').getContext("2d"); var c = document.getElementById("myCanvas"); var control = document.getElementsByClassName("control")[0]; var saveimgs = document.getElementsByClassName("saveimgs")[0]; window.onload = function () { document.getElementById('myCanvas').setAttribute("width", $(window).width()-5); InitThis(); } function saveImageInfo(){ var image = c.toDataURL("image/png"); window.parent.document.getElementById('pbase64').value = image; window.parent.document.getElementById('phw').click(); return; var ctximg = document.createElement("span"); ctximg.innerHTML = "<img src='"+image+"' alt='from canvas'/>"; if(saveimgs.getElementsByTagName('span').length >= 1){ var span_old = saveimgs.getElementsByTagName("span")[0]; saveimgs.replaceChild(ctximg,span_old) } else{ saveimgs.appendChild(ctximg); } } var selected1,selected2; function aaa(){ var sel = document.getElementById('selWidth'); var value = sel.selectedIndex; return selected1 = sel[value].value; } function aaa2(){ var sel2 = document.getElementById('selColor'); var value = sel2.selectedIndex; return selected2 = sel2[value].value; } function InitThis() { // 触摸屏 c.addEventListener('touchstart', function (event) { console.log(1) if (event.targetTouches.length == 1) { event.preventDefault();// 阻止浏览器默认事件,重要 var touch = event.targetTouches[0]; mousePressed = true; Draw(touch.pageX - this.offsetLeft, touch.pageY - this.offsetTop, false); } },false); c.addEventListener('touchmove', function (event) { console.log(2) if (event.targetTouches.length == 1) { event.preventDefault();// 阻止浏览器默认事件,重要 var touch = event.targetTouches[0]; if (mousePressed) { Draw(touch.pageX - this.offsetLeft, touch.pageY - this.offsetTop, true); } } },false); c.addEventListener('touchend', function (event) { console.log(3) if (event.targetTouches.length == 1) { event.preventDefault();// 阻止浏览器默认事件,防止手写的时候拖动屏幕,重要 mousePressed = false; } },false); /*c.addEventListener('touchcancel', function (event) { console.log(4) mousePressed = false; },false);*/ // 鼠标 c.onmousedown = function (event) { mousePressed = true; Draw(event.pageX - this.offsetLeft, event.pageY - this.offsetTop, false); }; c.onmousemove = function (event) { if (mousePressed) { Draw(event.pageX - this.offsetLeft, event.pageY - this.offsetTop, true); } }; c.onmouseup = function (event) { mousePressed = false; }; } function Draw(x, y, isDown) { if (isDown) { ctx.beginPath(); ctx.strokeStyle = selected2; ctx.lineWidth = selected1; ctx.lineJoin = "round"; ctx.moveTo(lastX, lastY); ctx.lineTo(x, y); ctx.closePath(); ctx.stroke(); } lastX = x; lastY = y; } function clearArea() { ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); // 清除签名图片 if(saveimgs.getElementsByTagName('span').length >= 1){ var clearImg = saveimgs.getElementsByTagName('span')[0]; saveimgs.removeChild(clearImg); } } </script> </html>
该页面需要引用 jquery-3.3.1.min.js
前端引用
前端页面除嵌入手写功能页面外,iframe的父窗口需要放置两个元素,一个用于存储手写提交后的Base64数据的 Asp.net 服务器按钮文本框元素,另一个是用于模拟调用服务器事件的 Asp.net 服务器按钮元素。
引用代码如下:
<div style=" text-align:center"> <iframe width="520" height="350" id="hw" runat="server" scrolling="no" frameborder="0" src="/cc/module/hw/hw.aspx" ></iframe> <asp:TextBox ID="pbase64" TextMode="MultiLine" style="display:none" runat="server" ></asp:TextBox> <asp:button ID="phw" OnClientClick="waittip()" text="后台处理" runat="server" style="display:none" onclick="phw_Click" /> </div>
后端处理
手写功能中的提交执行代码将调用如下:
window.parent.document.getElementById('pbase64').value = image; window.parent.document.getElementById('phw').click();
其中 pbase64 和 phw 控件为服务器控件,可直接模拟调用 phw 按钮的服务器 click,在这之前其还可以自动处理 OnClientClick事件以显示等待界面。请注意 waittip() 执行了一段 javascript 脚本,如下:
function waittip() { layer.open({ type: 2, shadeClose: false, content: '正在分析,请稍候...' }); }
这其中引入了 Layer 弹出层技术,关于 Layer 弹层组件请参照我的文章《改造 layer 弹层移动版组件》
这是调用服务器Click的事件处理代码,将上传的Base64图片转为两种格式的图片文件(PNG和JPEG)。代码如下:
protected void phw_Click(object sender, EventArgs e) { string mtfilename = "d:\\hw_" + System.Guid.NewGuid().ToString() + ".png"; string mtfilename2 = "d:\\hw_" + System.Guid.NewGuid().ToString() + ".jpg"; string dummyData = pbase64.Text.Trim().Replace("data:image/png;base64,", ""); Base64StringToImage(dummyData, mtfilename); if (File.Exists(mtfilename)==false) { base64.ImageUrl = dummyData; layer.open("保存手写图片失败,请重试并提交。" , "'确定'", "error"); return; } System.Drawing.Image img = System.Drawing.Image.FromFile(mtfilename); using (var b = new System.Drawing.Bitmap(img.Width, img.Height)) { b.SetResolution(img.HorizontalResolution, img.VerticalResolution); using (var g = System.Drawing.Graphics.FromImage(b)) { g.Clear(System.Drawing.Color.White); g.DrawImageUnscaled(img, 0, 0); } b.Save(mtfilename2, System.Drawing.Imaging.ImageFormat.Jpeg); } }
小结
本示例中的前后端代码仅为展示参考,手写功能在支持触屏的设备可以支持手写,也可以用鼠标进行模拟。
服务器调用示例中需要使用 Base64StringToImage(dummyData, mtfilename); 方法由Base64数据转化为图片文件,代码如下:
public bool Base64StringToImage(string strbase64, string outputFilename) { byte[] arr = Convert.FromBase64String(strbase64); MemoryStream ms = new MemoryStream(arr); System.Drawing.Image img = System.Drawing.Image.FromStream(ms); img.Save(outputFilename); img.Dispose(); if (File.Exists(outputFilename)) { return true; } return false; }
到此这篇关于C#结合JavaScript实现手写板签名效果的文章就介绍到这了,更多相关C# JavaScript手写签名内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!