SignatureAppearance.vb
''
'' This code is part of Document Solutions for PDF demos.
'' Copyright (c) MESCIUS inc. All rights reserved.
''
Imports System.IO
Imports System.Drawing
Imports GrapeCity.Documents.Drawing
Imports GrapeCity.Documents.Pdf
Imports GrapeCity.Documents.Pdf.AcroForms
Imports GrapeCity.Documents.Pdf.Graphics
Imports GrapeCity.Documents.Text
Imports System.Security.Cryptography.X509Certificates
Imports GCTEXT = GrapeCity.Documents.Text
Imports GCDRAW = GrapeCity.Documents.Drawing

'' This sample demonstrates how to create and sign a PDF with a .pfx file,
'' specifying a custom AppearanceStream to represent the signature.
'' This sample is similar to SignDoc, except that it adds the AppearanceStream.
Public Class SignatureAppearance
    Function CreatePDF(ByVal stream As Stream) As Integer
        Dim doc = New GcPdfDocument()
        Dim page = doc.NewPage()
        Dim tf = New TextFormat() With {.Font = StandardFonts.Times, .FontSize = 14}
        page.Graphics.DrawString(
            "Hello, World!" + vbLf +
            "Signed by DsPdfWeb SignatureAppearance sample.",
            tf, New PointF(72, 72))

        '' Init a test certificate:
        Dim pfxPath = Path.Combine("Resources", "Misc", "DsPdfTest.pfx")
        Dim cert = New X509Certificate2(File.ReadAllBytes(pfxPath), "qq",
            X509KeyStorageFlags.MachineKeySet Or X509KeyStorageFlags.PersistKeySet Or X509KeyStorageFlags.Exportable)
        Dim sp = New SignatureProperties() With {
            .SignatureBuilder = New Pkcs7SignatureBuilder() With {
                .CertificateChain = New X509Certificate2() {cert}
            },
            .Location = "DsPdfWeb Demo Browser",
            .SignerName = "DsPdfWeb",
            .SigningDateTime = Util.TimeNow()
        }

        '' Create a signature field to hold the signature:
        Dim sf = New SignatureField()
        '' Add the signature field to the document:
        doc.AcroForm.Fields.Add(sf)
        '' Connect the signature field and signature props:
        sp.SignatureField = sf

        '' Set up the signature field:
        sf.Widget.Rect = New RectangleF(page.Size.Width - 72 * 4, 72 * 2, 72 * 3, 72)
        sf.Widget.Page = page
        '' Widget visual props will be overridden by sf.Widget.AppearanceStreams.Normal.Default set below:
        sf.Widget.BackColor = Color.PeachPuff
        sf.Widget.Border = New GrapeCity.Documents.Pdf.Annotations.Border() With
            {
                .Color = Color.SaddleBrown,
                .Width = 3
            }
        sf.Widget.ButtonAppearance.Caption = $"Signer: {sp.SignerName}{vbLf}Location: {sp.Location}"
        '' Create custom signature appearance stream:
        Dim rc = New RectangleF(PointF.Empty, sf.Widget.Rect.Size)
        Dim fxo = New FormXObject(doc, rc)
        rc.Inflate(-4, -4)
        fxo.Graphics.FillEllipse(rc, Color.CornflowerBlue)
        fxo.Graphics.DrawEllipse(rc, New GCDRAW.Pen(Color.RoyalBlue, 3))
        rc.Inflate(-5, -5)
        fxo.Graphics.DrawEllipse(rc, New GCDRAW.Pen(Color.LightSteelBlue, 1))
        fxo.Graphics.DrawString($"Signed by {sp.SignerName}{vbLf}on {Util.TimeNow():yyyy-MM-dd}.",
            New TextFormat() With
            {
                .FontName = "Times New Roman",
                .FontSize = 14,
                .FontItalic = True,
                .ForeColor = Color.Navy
            },
            fxo.Bounds,
            TextAlignment.Center, ParagraphAlignment.Center, False)
        sf.Widget.AppearanceStreams.Normal.Default = fxo

        '' Reset signature appearance so that the widget appearance stream is used:
        sp.SignatureAppearance = Nothing

        '' Sign and save the document:
        '' NOTES:
        '' - Signing and saving is an atomic operation, the two cannot be separated.
        '' - The stream passed to the Sign() method must be readable.
        doc.Sign(sp, stream)

        '' Done (the generated and signed docment has already been saved to 'stream').
        Return doc.Pages.Count
    End Function
End Class