当前位置: 代码网 > it编程>编程语言>Asp.net > C# WinForm实现画笔签名功能

C# WinForm实现画笔签名功能

2024年11月20日 Asp.net 我要评论
需求我的文章《c# 结合javascript实现手写板签名并上传到服务器》主要介绍了 web 版的需求实现,本文应项目需求介绍如何通过 c# winform 通过画布画笔实现手写签名,并在开发过程中解

需求

我的文章 《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;
            }
        }

画笔类主要包括 :

序号属性名类型说明
1lastpointpoint记录最后一次画笔的坐标点,并结合 drawline 方法画出想要的线段
2colorcolor画笔的颜色,默认为黑色
3widthint画笔的粗线,默认为2,1为最细

实现绘图,主要是通过画笔类,在canvaspanel 的鼠标按下、鼠标移动、和鼠标抬起事件定义相关操作。

序号事件名说明
1canvaspanel_mousedown记住鼠标是否按下,将 bool ismousedown 置为true,另一个关键功能是将按下的点(point),赋值到画笔的 lastpoint 属性,以备后续绘制线条使用
2canvaspanel_mousemove判断 ismousedown 标志,如果为 true 则引入画布图像,从最后一次的point结合当前鼠标的point 进行 drawline 操作,并形成新的位图数据
3canvaspanel_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 选项,可以导出三种类型的形式数据,如下表:

序号事件名说明
1radiobutton1直接导出成文件(jpeg类型)
2radiobutton2导出二进制数据 (byte[])
3radiobutton3导出 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#画笔签名的资料请关注代码网其它相关文章!

(0)

相关文章:

  • C#处理XML文件的示例详解

    C#处理XML文件的示例详解

    一、基本介绍可扩展标记语言(英语:extensible markup language,简称:xml),是一种标记语言。标记指计算机所能理解的信息符号,通过此种... [阅读全文]
  • C# WPF自制简单的批注工具

    C# WPF自制简单的批注工具

    在教学和演示中,我们通常需要对重点进行批注,下载安装第三方工具批注显得很麻烦。本篇使用wpf开发了一个批注工具,工具小巧,功能丰富,非常使用日常免费使用,或者进... [阅读全文]
  • C# WPF自制白板工具

    C# WPF自制白板工具

    随着电子屏幕技术的发展,普通的黑板已不再适用现在的教学和演示环境,电子白板应运而生。本篇使用wpf开发了一个电子白板工具,功能丰富,非常使用日常免费使用,或者进... [阅读全文]
  • .NET 9 中 LINQ 新增功能实现过程

    linq 介绍语言集成查询 (linq) 是一系列直接将查询功能集成到 c# 语言的技术统称。 数据查询历来都表示为简单的字符串,没有编译时类型检查或 intellisense 支…

    2024年11月25日 编程语言
  • 如何使用 .NET 创建新的 WPF 应用

    前言在本教程中,你将了解:创建新的 wpf 应用。向窗口添加控件。处理控制事件以提供应用功能。运行应用。下面是在学习本教程时创建的应用的预览版:一、先决条件visual studi…

    2024年11月25日 编程语言
  • .NET Core 特性(Attribute)底层原理解析

    .NET Core 特性(Attribute)底层原理解析

    attribute的使用场景attribute不仅仅局限于c#中,在整个.net框架中都提供了非常大的拓展点,任何地方都有attribute的影子编译器层比如 ... [阅读全文]

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com