SignIncremental.vb
'' 完毕:
Imports System.IO
Imports System.Drawing
Imports GrapeCity.Documents.Pdf
Imports GrapeCity.Documents.Pdf.AcroForms
Imports GrapeCity.Documents.Text
Imports System.Security.Cryptography.X509Certificates

'' 此示例​​生成并签署 PDF(使用与 SignDoc 示例类似的代码),
'' 然后使用第二个签名对生成的 PDF 进行签名,而不会使原始文件失效
'' 签名,通过使用增量更新(使用 Sign() 方法时的默认设置)。
Public Class SignIncremental
    Function CreatePDF(ByVal stream As Stream) As Integer
        Dim doc = New GcPdfDocument()

        '' 加载签名文档(我们使用类似于SignDoc示例的代码):
        doc.Load(CreateAndSignPdf())

        '' 初始化第二个证书:
        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()
        }

        '' 找到第二个(尚未填写)签名字段:
        Dim sfld2 = CType(doc.AcroForm.Fields("SecondSignature"), SignatureField)
        '' 连接签名字段和签名属性:
        If sfld2 Is Nothing Then
            Throw New Exception("Unexpected: could not find 'SecondSignature' field")
        End If
        sp2.SignatureField = sfld2

        '' 签署并保存文档:
        doc.Sign(sp2, stream)

        '' 倒回流以读取刚刚创建的文档
        '' 进入另一个 GcPdfDocument 并验证所有签名:
        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
        ''
        '' 完成(生成并签名的文档已保存到“流”)。
        Return doc.Pages.Count
    End Function

    '' 这个方法与SignDoc示例几乎完全相同,
    '' 但添加了第二个签名字段(但不签名):
    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("你好世界!" +
            "",
            tf, New PointF(72, 72))

        '' 初始化测试证书:
        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()
        }

        '' 初始化一个签名字段来保存签名:
        Dim sf = New SignatureField()
        sf.Widget.Rect = New RectangleF(72, 72 * 2, 72 * 4, 36)
        sf.Widget.Page = page
        sf.Widget.BackColor = Color.LightSeaGreen
        '' 将签名字段添加到文档中:
        doc.AcroForm.Fields.Add(sf)

        '' 连接签名字段和签名属性:
        sp.SignatureField = sf

        '' 添加第二个签名字段:
        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
        '' 将签名字段添加到文档中:
        doc.AcroForm.Fields.Add(sf2)

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