SignIncremental.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.Pdf
Imports GrapeCity.Documents.Pdf.AcroForms
Imports GrapeCity.Documents.Text
Imports System.Security.Cryptography.X509Certificates

'' This sample generates and signs a PDF (using code that is similar to SignDoc sample),
'' and then signs the generated PDF with a second signature without invalidating the original
'' signature, by using incremental update (default when using the Sign() method).
Public Class SignIncremental
    Function CreatePDF(ByVal stream As Stream) As Integer
        Dim doc = New GcPdfDocument()

        '' Load a signed document (we use code similar to the SignDoc sample):
        doc.Load(CreateAndSignPdf())

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

        '' Find the 2nd (not yet filled) signature field:
        Dim sfld2 = CType(doc.AcroForm.Fields("SecondSignature"), SignatureField)
        '' Connect the signature field and signature props:
        If sfld2 Is Nothing Then
            Throw New Exception("Unexpected: could not find 'SecondSignature' field")
        End If
        sp2.SignatureField = sfld2

        '' Sign and save the document:
        doc.Sign(sp2, stream)

        '' Rewind the stream to read the document just created
        '' into another GcPdfDocument and verify all signatures:
        stream.Seek(0, SeekOrigin.Begin)
        Dim doc2 = New GcPdfDocument()
        doc2.Load(stream)
        For Each fld In doc2.AcroForm.Fields
            If TypeOf fld Is SignatureField Then
                Dim sfld = CType(fld, SignatureField)
                If Not sfld.Value.VerifySignatureValue() Then
                    Throw New Exception($"Failed to verify signature for field {sfld.Name}")
                End If
            End If
        Next
        ''
        '' Done (the generated and signed document has already been saved to 'stream').
        Return doc.Pages.Count
    End Function

    '' This method is almost exactly the same as the SignDoc sample,
    '' but adds a second signature field (does not sign it though):
    Private Function CreateAndSignPdf() As Stream
        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 TWICE by DsPdfWeb SignIncremental 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()
        }

        '' Init a signature field to hold the signature:
        Dim sf = New SignatureField()
        sf.Widget.Rect = New RectangleF(72, 72 * 2, 72 * 4, 36)
        sf.Widget.Page = page
        sf.Widget.BackColor = Color.LightSeaGreen
        '' Add the signature field to the document:
        doc.AcroForm.Fields.Add(sf)

        '' Connect the signature field and signature props:
        sp.SignatureField = sf

        '' Add a second signature field:
        Dim sf2 = New SignatureField() With {.Name = "SecondSignature"}
        sf2.Widget.Rect = New RectangleF(72, 72 * 3, 72 * 4, 36)
        sf2.Widget.Page = page
        sf2.Widget.BackColor = Color.LightYellow
        '' Add the signature field to the document:
        doc.AcroForm.Fields.Add(sf2)

        Dim ms = New MemoryStream()
        doc.Sign(sp, ms)
        Return ms
    End Function
End Class