How to draw a signature and save it to disc as a Bitmap?

前端 未结 3 1313
伪装坚强ぢ
伪装坚强ぢ 2021-01-15 23:46

I\'m trying to do a signature capture program and save the customer signature to a PNG or BMP format. I have the Picturebox code working great and

3条回答
  •  滥情空心
    2021-01-16 00:19

    Never use [Control].CreateGraphics, unless you need this object for immediate use in a specific environment. To measure the size of text when drawn in a specific graphics context, for example.
    When you need the drawing to persist, as painting on the surface of a control, use the Graphics object provided by the PaintEventArgs of the Paint event (or similar event, as the DrawItem event of the ComboBox, ListBox, ListView controls).
    You'll find this kind of recommendations all over SO (and the Web, in general).

    How to proceed:

    1. We need an object that can store the Mouse/Pen movements that define a hand-made curve.
    2. The object needs to store a new curve definition each time the left button of the mouse is released (or the Pen touch is lost and re-acquired).
    3. We need a Graphics object that can convert the points defined by the Mouse/Pen movements to Bezier curves (combinations of curves are often referred to as Paths in vector graphics).

    Here, the object that stores the movements is a Dictionary(Of Integer, List(Of Point)), where the Key represents a curve and the Value represents the collection of Points that define that curve.
    Each time the Left Button of the Mouse is pressed, a new Key is created and a new List(Of Point) is associated with the Key.
    When the Mouse/Pen is moved, the new Point location is added to the current curve's List(Of Point).

    The GraphicsPath class can convert the List(Of Point) collection to Control Points of a Bezier curve, using the GraphicsPath.AddCurve() method.
    This method accepts an array of Points and a Tension value as arguments. The Tension is a value between 0 and 1 that defines the amount of bending applied to a curve when connecting Points. A values of 0.5f is used here.

    When we need to paint the drawing on a Bitmap to save the results to disc, we apply the same logic to the Graphics object derived, in this case, from a Bitmap object.
    Thus, just one method is used to draw both on the surface of a Control and onto a Bitmap object.
    The DrawSignature(g As Graphics) method in this code.

    This is how it works:

    Code that reproduces the procedure described:

    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
        Using 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 = New Bitmap(imgSignature)
            End Using
        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.CompositingMode = CompositingMode.SourceOver
        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
    

提交回复
热议问题