winforms 如何绘制签名并将其保存为位图?

kb5ga3dv  于 2022-11-25  发布在  其他
关注(0)|答案(3)|浏览(216)

我正在尝试执行一个签名捕获程序,并将客户签名保存为PNGBMP。我的Picturebox代码运行良好,结果比使用draw效果更好。我无法保存图像。

Imports System.Drawing
Public Class Form1
    Dim color As System.Drawing.Pen = Pens.Black
    Dim bmp As Bitmap

    Private Sub form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        bmp = New Bitmap(PictureBox1.Width, PictureBox1.Height)
        PictureBox1.Image = bmp
    End Sub

    Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
        Static last As New Point
        If e.Button = Windows.Forms.MouseButtons.Left Then
            PictureBox1.CreateGraphics.DrawLine(color, last.X, last.Y, e.X, e.Y)
        End If
        last = e.Location
    End Sub

    Private Sub CmdClear_Click(sender As Object, e As EventArgs) Handles cmdClear.Click
        bmp = New Bitmap(PictureBox1.Width, PictureBox1.Height)
        PictureBox1.Image = bmp
    End Sub

    Private Sub CmdSave_Click(sender As Object, e As EventArgs) Handles cmdSave.Click
        If PictureBox1.Image IsNot Nothing Then
            bmp = PictureBox1.Image
            bmp.Save("c:\temp\test1.bmp")
        End If
    End Sub
End Class

我想看看签名的图像。

zbq4xfa0

zbq4xfa01#

切勿使用**[Control].CreateGraphics,除非您需要在特定环境中立即使用此对象。例如,在特定图形上下文中绘制时测量文本的大小。
当您需要持续绘制(如同在控件的表面上绘制)时,请使用Paint事件(或类似事件,如ComboBox、ListBox、ListView控件的DrawItem事件)的PaintEventArgs所提供的Graphics对象。
您会在SO(以及Web,一般而言)上找到这种推荐。
如何继续:
1.我们需要一个对象,它可以存储鼠标/笔的移动,这些移动定义了一条手工制作的曲线。
1.每次释放鼠标左键(或丢失并重新获取触控笔)时,对象都需要存储新的曲线定义。
1.我们需要一个Graphics对象,它可以将由鼠标/笔移动创建的点定义的基数样条曲线转换为Bezier curves(曲线的组合-表示一系列平滑矢量线的轮廓-在矢量图形中通常称为 * 路径 )。
这里,存储移动的对象是
*Dictionary(Of Integer, List(Of Point))
,其中**Key表示曲线,Value表示定义该曲线的Point的集合。
每次按下鼠标左键时,都会创建一个新的Key,并将一个新的List(Of Point)Key关联。
移动鼠标/笔时,新的点位置将添加到当前曲线的List(Of Point)
GraphicsPath类别可以使用GraphicsPath.AddCurve()方法,将List(Of Point)集合转换为贝兹曲缐的控制点。
此方法接受一个Points数组和一个
Tension值作为参数。Tension是一个介于01之间的值,用于定义连接Points时应用于曲线的弯曲量。此处使用的值为0.5f
►当我们需要在Bitmap上绘制图形以将结果保存到磁盘时,我们将相同的逻辑应用于Graphics对象,在本例中,该对象是从Bitmap对象派生的。
因此,只需使用一种方法即可在Control的表面和Bitmap对象上进行绘制。
此代码中的
DrawSignature(g As Graphics)**方法。
它是这样工作的:

重现所述程序的代码
**pBoxSignature**是绘制签名的PictureBox
**pBoxSavedSignature**是用于显示最后保存的图像的(较小的)PictureBox
**btnClearSignature**是用于清除签名的按钮
**btnSaveSignature**是用于将签名保存到新图像的按钮
**txtSignatureFileName**是用于输入签名文件名的文本框

Private signatureObject As New Dictionary(Of Integer, List(Of Point))
Private signaturePen As New Pen(Color.Black, 4)
Private currentCurvePoints As List(Of Point)
Private currentCurve As Integer = -1

Private Sub pBoxSignature_MouseDown(sender As Object, e As MouseEventArgs) Handles pBoxSignature.MouseDown
    currentCurvePoints = New List(Of Point)
    currentCurve += 1
    signatureObject.Add(currentCurve, currentCurvePoints)
End Sub

Private Sub pBoxSignature_MouseMove(sender As Object, e As MouseEventArgs) Handles pBoxSignature.MouseMove
    If e.Button <> MouseButtons.Left OrElse currentCurve < 0 Then Return
    signatureObject(currentCurve).Add(e.Location)
    pBoxSignature.Invalidate()
End Sub

Private Sub btnClearSignature_Click(sender As Object, e As EventArgs) Handles btnClearSignature.Click
    currentCurve = -1
    signatureObject.Clear()
    pBoxSignature.Invalidate()
End Sub

Private Sub btnSaveSignature_Click(sender As Object, e As EventArgs) Handles btnSaveSignature.Click
    Dim signatureFileName = txtSignatureFileName.Text.Trim()
    If String.IsNullOrEmpty(signatureFileName) Then Return
    If currentCurve < 0 OrElse signatureObject(currentCurve).Count = 0 Then Return

    imgSignature As Bitmap = New Bitmap(pBoxSignature.Width, pBoxSignature.Height, PixelFormat.Format32bppArgb) 
    Using g As Graphics = Graphics.FromImage(imgSignature)
        DrawSignature(g)

        Dim signaturePath As String = Path.Combine(Application.StartupPath, $"{signatureFileName}.png")
        imgSignature.Save(signaturePath, ImageFormat.Png)
        pBoxSavedSignature.Image?.Dispose()
        pBoxSavedSignature.Image = imgSignature
    End Using
End Sub

Private Sub pBoxSignature_Paint(sender As Object, e As PaintEventArgs) Handles pBoxSignature.Paint
    If currentCurve < 0 OrElse signatureObject(currentCurve).Count = 0 Then Return
    DrawSignature(e.Graphics)
End Sub

Private Sub DrawSignature(g As Graphics)
    g.CompositingQuality = CompositingQuality.HighQuality
    g.SmoothingMode = SmoothingMode.AntiAlias

    For Each curve In signatureObject
        If curve.Value.Count < 2 Then Continue For
        Using gPath As New GraphicsPath()
            gPath.AddCurve(curve.Value.ToArray(), 0.5F)
            g.DrawPath(signaturePen, gPath)
        End Using
    Next
End Sub

C#版本

private Dictionary<int, List<Point>> signatureObject = new Dictionary<int, List<Point>>();
private Pen signaturePen = new Pen(Color.Black, 4);
private List<Point> currentCurvePoints = null;
private int currentCurve = -1;

private void pBoxSignature_MouseDown(object sender, MouseEventArgs e)
{
    currentCurvePoints = new List<Point>();
    currentCurve += 1;
    signatureObject.Add(currentCurve, currentCurvePoints);
}

private void pBoxSignature_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button != MouseButtons.Left || currentCurve < 0) return;
    signatureObject[currentCurve].Add(e.Location);
    pBoxSignature.Invalidate();
}

private void btnClearSignature_Click(object sender, EventArgs e)
{
    currentCurve = -1;
    signatureObject.Clear();
    pBoxSignature.Invalidate();
}

private void btnSaveSignature_Click(object sender, EventArgs e)
{
    string signatureFileName = txtSignatureFileName.Text.Trim();
    if (string.IsNullOrEmpty(signatureFileName)) return;
    if (currentCurve < 0 || signatureObject[currentCurve].Count == 0) return;

    var imgSignature = new Bitmap(pBoxSignature.Width, pBoxSignature.Height, PixelFormat.Format32bppArgb);
    using (var g = Graphics.FromImage(imgSignature)) {
        DrawSignature(g);
        string signaturePath = Path.Combine(Application.StartupPath, $"{signatureFileName}.png");
        imgSignature.Save(signaturePath, ImageFormat.Png);
        pBoxSavedSignature.Image?.Dispose();
        pBoxSavedSignature.Image = imgSignature;
    }
}

private void pBoxSignature_Paint(object sender, PaintEventArgs e)
{
    if (currentCurve < 0 || signatureObject[currentCurve].Count == 0) return;
    DrawSignature(e.Graphics);
}

private void DrawSignature(Graphics g)
{
    // In case you have composited background
    g.CompositingQuality = CompositingQuality.HighQuality;
    g.SmoothingMode = SmoothingMode.AntiAlias;

    foreach (var curve in signatureObject) {
        if (curve.Value.Count < 2) continue;

        using (var gPath = new GraphicsPath()) {
            gPath.AddCurve(curve.Value.ToArray(), 0.5f);
            g.DrawPath(signaturePen, gPath);
        }
    }
}
zsohkypk

zsohkypk2#

当想要保存为BMP时,背景需要是白色的,因为BMP不支持透明度。

Dim Brsh As SolidBrush = New SolidBrush(Color.White)
g.FillRectangle(Brsh, 0, 0, pBoxSignature.Width, pBoxSignature.Height)
g.DrawPath(signaturePen, gPath)

但是,现在我不再能够拿起我的笔划,否则所有以前的笔划被删除/清除。(意思是名字和姓氏需要写没有拿起笔)可能有人有更多的图像知识也许看到一个原因,并指出我在解决方案的方向?
更新:工作代码
代码如下:

Using imgSignature As Bitmap = New Bitmap(pBoxSignature.Width, pBoxSignature.Height, PixelFormat.Format32bppRgb)
    Using g As Graphics = Graphics.FromImage(imgSignature)
        g.FillRectangle(Brsh, 0, 0, pBoxSignature.Width, pBoxSignature.Height)
        Call DrawSignature(g)
    End Using
    imgSignature.Save(signaturePath, ImageFormat.Bmp)
    pBoxSavedSignature.Image = New Bitmap(imgSignature)
End Using
y4ekin9u

y4ekin9u3#

谢谢吉米。
如果有人在C#中需要它:

public partial class FSignature : Form
{
    private Dictionary<int, List<Point>> signatureObject = new Dictionary<int, List<Point>>();
    private Pen signaturePen = new Pen(Color.Black, 4);
    private List<Point> currentCurvePoints;
    private int currentCurve = -1;

    public FSignature()
    {
        InitializeComponent();
    }



    private void pBoxSignature_MouseDown(object sender, MouseEventArgs e)
    {
        currentCurvePoints = new List<Point>();
        currentCurve += 1;
        signatureObject.Add(currentCurve, currentCurvePoints);
    }

    private void pBoxSignature_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button != MouseButtons.Left || currentCurve < 0)
            return;
        signatureObject[currentCurve].Add(e.Location);
        pBoxSignature.Invalidate();
    }

    private void btnClearSignature_Click(object sender, EventArgs e)
    {
        currentCurve = -1;
        signatureObject.Clear();
        pBoxSignature.Invalidate();
    }

    private void btnSaveSignature_Click(object sender, EventArgs e)
    {
        var signatureFileName = txtSignatureFileName.Text.Trim();
        if (string.IsNullOrEmpty(signatureFileName))
            return;
        if (currentCurve < 0 || signatureObject[currentCurve].Count == 0)
            return;
        using (Bitmap imgSignature = new Bitmap(pBoxSignature.Width, pBoxSignature.Height, PixelFormat.Format32bppArgb))
        {
            using (Graphics g = Graphics.FromImage(imgSignature))
            {
                DrawSignature(g);
                string signaturePath = Path.Combine(Application.StartupPath, $"{signatureFileName}.png");
           
                imgSignature.Save(signaturePath, ImageFormat.Png);
                pBoxSavedSignature.Image = new Bitmap(imgSignature);
            }
        }
    }

    private void pBoxSignature_Paint(object sender, PaintEventArgs e)
    {
        if (currentCurve < 0 || signatureObject[currentCurve].Count == 0)
            return;
        DrawSignature(e.Graphics);
    }

    private void DrawSignature(Graphics g)
    {
        g.CompositingMode = CompositingMode.SourceOver;
        g.CompositingQuality = CompositingQuality.HighQuality;
        g.SmoothingMode = SmoothingMode.AntiAlias;
        foreach (var curve in signatureObject)
        {
            if (curve.Value.Count < 2)
                continue;
            using (GraphicsPath gPath = new GraphicsPath())
            {
                gPath.AddCurve(curve.Value.ToArray(), 0.5F);
                g.DrawPath(signaturePen, gPath);
            }
        }
    }

}

相关问题