需求
我的文章 《c# 结合javascript实现手写板签名并上传到服务器》主要介绍了 web 版的需求实现,本文应项目需求介绍如何通过 c# winform 通过画布画笔实现手写签名,并在开发过程中解决遇到的一些格式转换的问题,提供一些思路。
实现效果
签名功能的显示界面如下图:
该效果主要实现如下功能:
1、提供画布,设计画笔类,实现画笔签名
2、点击重签按钮清空画布
3、点击确认按钮保存画布位图到指定的格式(提供三种保存类型,文件,二进制数据和base64编码)
开发运行环境
操作系统: windows server 2019 datacenter
手写触屏设备:microsoft surface pro 9
.net版本: .netframework4.0 或以上
开发工具:vs2019 c#
设计实现
界面布局
主要在winform上放置如下控件,name 为 canvaspanel 的 system.windows.forms.panel控件,一些label控件、radiobutton控件和两个功能按钮button控件,如下图:
初始化
form1 初始化如下变量:
bool ismousedown = false; // 判断鼠标或手指是否按下,按下为 true graphics canvas = null; // 定义绘图画布 image bmpdata = null; // 定义 image 图像,将来导出时使用
实例化变量的过程中 new bitmap ,则产生的默认格式为 system.drawing.imaging.imageformat.memorybmp 格式,这会产生一个问题,保存的位图是全黑色。因此一个解决的思路是先临时创建一个白色背景的jpeg图片,图片的大小取决于panel控件的宽度和高度,然后再将画布的图像 bmpdata 变量,实例化创建引用这个临时图片的路径。
示例代码如下:
public partial class form1 : form { bool ismousedown = false; graphics canvas = null; image bmpdata = null; public form1() { initializecomponent(); canvas = canvaspanel.creategraphics(); string tmpjpg = application.startuppath + "\\tmpimg\\" + system.guid.newguid().tostring() + ".jpg"; using (bitmap bitmap = new bitmap(canvaspanel.width, canvaspanel.height)) { using (graphics graphics = graphics.fromimage(bitmap)) { graphics.clear(color.white); } bitmap.save(tmpjpg, imageformat.jpeg); } bmpdata = new bitmap(tmpjpg); } }
画笔绘图
graphics canvas 为canvaspanel控件创建的画布,首先定义实现一个画笔类,代码如下:
public static class signpen { public static point lastpoint { get; set; } public static color color { get; set; } public static int width { get; set; } static signpen() { color = color.black; width = 2; } }
画笔类主要包括 :
序号 | 属性名 | 类型 | 说明 |
---|---|---|---|
1 | lastpoint | point | 记录最后一次画笔的坐标点,并结合 drawline 方法画出想要的线段 |
2 | color | color | 画笔的颜色,默认为黑色 |
3 | width | int | 画笔的粗线,默认为2,1为最细 |
实现绘图,主要是通过画笔类,在canvaspanel 的鼠标按下、鼠标移动、和鼠标抬起事件定义相关操作。
序号 | 事件名 | 说明 |
---|---|---|
1 | canvaspanel_mousedown | 记住鼠标是否按下,将 bool ismousedown 置为true,另一个关键功能是将按下的点(point),赋值到画笔的 lastpoint 属性,以备后续绘制线条使用 |
2 | canvaspanel_mousemove | 判断 ismousedown 标志,如果为 true 则引入画布图像,从最后一次的point结合当前鼠标的point 进行 drawline 操作,并形成新的位图数据 |
3 | canvaspanel_mouseup | 将 bool ismousedown 置为 false,不再进行绘制 |
示例代码如下:
private void canvaspanel_mousedown(object sender, mouseeventargs e) { if (e.button == mousebuttons.left) { ismousedown = true; signpen.lastpoint = new point(e.x, e.y); } } private void canvaspanel_mousemove(object sender, mouseeventargs e) { if (ismousedown == true) { graphics gf = graphics.fromimage(bmpdata); //设置高质量插值法 gf.interpolationmode = system.drawing.drawing2d.interpolationmode.high; //设置高质量,低速度呈现平滑程度 gf.smoothingmode = system.drawing.drawing2d.smoothingmode.antialias; pen pen = new pen(signpen.color, signpen.width); point curpoint = new point(e.x, e.y); gf.drawline(pen, signpen.lastpoint, curpoint); signpen.lastpoint = curpoint; canvas.drawimage(bmpdata, 0,0); } } private void canvaspanel_mouseup(object sender, mouseeventargs e) { ismousedown = false; }
清空画布
可通过点击“重签” 按钮,清空画布,实现如初始化功能,代码如下:
string tmpjpg = application.startuppath + "\\tmpimg\\" + system.guid.newguid().tostring() + ".jpg"; using (bitmap bitmap = new bitmap(canvaspanel.width, canvaspanel.height)) { using (graphics graphics = graphics.fromimage(bitmap)) { graphics.clear(color.white); } bitmap.save(tmpjpg, imageformat.jpeg); } bmpdata = new bitmap(tmpjpg); canvas.drawimage(bmpdata, 0,0);
导出位图数据
绘制完成,我们就需要将 bmpdata 位图变量数据导出我们想要的格式,为了便于演示,我们设置了一组 radiobutton 选项,可以导出三种类型的形式数据,如下表:
序号 | 事件名 | 说明 |
---|---|---|
1 | radiobutton1 | 直接导出成文件(jpeg类型) |
2 | radiobutton2 | 导出二进制数据 (byte[]) |
3 | radiobutton3 | 导出 base64 数据 (string类型) |
假设“确定”按钮 name 为 “button13”,并假设输出到d盘根目录下,示例代码如下:
private void button13_click(object sender, eventargs e) { string jpgfilename = "d:\\" + system.guid.newguid().tostring() + ".jpg"; bmpdata.save(jpgfilename,imageformat.jpeg); if (file.exists(jpgfilename) == false) { messagebox.show(string.format("保存文件至{0}失败。", jpgfilename)); return; } if (radiobutton1.checked == true) { messagebox.show(string.format("已成功保存至{0}。", jpgfilename)); } if (radiobutton2.checked == true) { byte[] bytes2=fe.getbinarydata(jpgfilename); messagebox.show(string.format("已成功保存为二进制数据,长度{0}。", bytes2.length)); } if (radiobutton3.checked == true) { string base64str = imgtobase64string(jpgfilename, false); messagebox.show(string.format("已成功保存为base64,长度{0}。", base64str.length)); } } public byte[] getbinarydata(string filename) { if(!file.exists(filename)) { return null; } try { filestream fs = new filestream(filename, filemode.open, fileaccess.read); byte[] imagedata = new byte[fs.length]; fs.read( imagedata, 0,convert.toint32(fs.length)); fs.close(); return imagedata; } catch(exception) { return null; } finally { } } public string imgtobase64string(string imagefilename, bool outfullstring = false) { try { system.drawing.bitmap bmp = new system.drawing.bitmap(imagefilename); memorystream ms = new memorystream(); // bmp.save(ms,imageformat.jpeg) system.drawing.imaging.imageformat iformat = system.drawing.imaging.imageformat.jpeg; string extension = system.io.path.getextension(imagefilename).replace(".", "").tolower(); if (extension == "bmp") { iformat = system.drawing.imaging.imageformat.bmp; } else if (extension == "emf") { iformat = system.drawing.imaging.imageformat.emf; } else if (extension == "exif") { iformat = system.drawing.imaging.imageformat.exif; } else if (extension == "gif") { iformat = system.drawing.imaging.imageformat.gif; } else if (extension == "icon") { iformat = system.drawing.imaging.imageformat.icon; } else if (extension == "png") { iformat = system.drawing.imaging.imageformat.png; } else if (extension == "tiff") { iformat = system.drawing.imaging.imageformat.tiff; } else if (extension == "wmf") { iformat = system.drawing.imaging.imageformat.wmf; } bmp.save(ms, iformat); byte[] arr = new byte[ms.length]; ms.position = 0; ms.read(arr, 0, (int)ms.length); ms.close(); bmp.dispose(); string rv = convert.tobase64string(arr); if (outfullstring == true) { rv = "data:image/" + extension + ";base64," + rv; } return rv; } catch (exception ex) { return null; } }
小结
对于 new bitmap 创建的位图,我们还可以使用 png 格式,以防止“黑图”的出现,我们在应用中可以灵活掌握,如下代码:
bitmap newimg = new bitmap(100,100); newimg.save("d:\\test.jpg", system.drawing.imaging.imageformat.png);
保存的数据,显示在画布上可采取如下方法:
1、文件型
system.drawing.image img2 = new bitmap(你的文件地址); canvas.drawimage(img2, 0, 0); messagebox.show("显示文件到画布成功!");
2、二进制型
byte[] bytes = 你的二进制数据; memorystream ms = new memorystream(bytes); system.drawing.image img = system.drawing.image.fromstream(ms); canvas.drawimage(img, 0, 0); messagebox.show("显示二进制到画布成功!");
3、base64型
string base64 = 你的base64数据; byte[] arr = convert.frombase64string(base64); memorystream ms2 = new memorystream(arr); system.drawing.image img2 = system.drawing.image.fromstream(ms2); canvas.drawimage(img2, 0, 0); messagebox.show("显示base64到画布成功!");
以上就是c# winform实现画笔签名功能的详细内容,更多关于c#画笔签名的资料请关注代码网其它相关文章!
发表评论