SignIncremental.vb
'' 
'' このコードは、DioDocs for PDF のサンプルの一部として提供されています。
'' © 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

'' このサンプルは、PDF を生成して署名し(SignDoc サンプルに似たコードを使用します)、
'' インクリメンタルアップデートを使用して(Sign() メソッドを使用する場合のデフォルト)、
'' オリジナルの署名を無効にすることなく、生成された PDF に2番目の証明書で署名します。
Public Class SignIncremental
    Function CreatePDF(ByVal stream As Stream) As Integer
        Dim doc = New GcPdfDocument()

        '' 署名されたドキュメントを読み込みます(SignDoc サンプルに似たコードを使用します)
        doc.Load(CreateAndSignPdf())

        '' 2番目の証明書を初期化します。
        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 = "DioDocs for PDF サンプルブラウザ",
            .SignerName = "作成者1",
            .SigningDateTime = Util.TimeNow()
        }

        '' 2番目用のまだ使われていない署名フィールドを探します。
        Dim sfld2 = CType(doc.AcroForm.Fields("SecondSignature"), SignatureField)
        '' 署名フィールドと署名プロパティを結びつけます。
        If sfld2 Is Nothing Then
            Throw New Exception("予期せぬエラー:'SecondSignature' フィールドが見つかりません。")
        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($"署名の検証に失敗しました。フィールド:{sfld.Name}")
                End If
            End If
        Next
        ''
        '' 終了(生成および署名された文書はすでに 'stream' に保存されています)。
        Return doc.Pages.Count
    End Function

    '' このメソッドは、SignDoc サンプルとほぼ同じですが、
    '' 2番目の署名フィールドを追加します(署名はしません)。
    Private Function CreateAndSignPdf() As Stream
        Dim doc = New GcPdfDocument()
        Dim page = doc.NewPage()
        Dim tf = New TextFormat() With {.FontName = "Yu Gothic", .FontSize = 12}
        page.Graphics.DrawString("サンプルコードにて以下に2つの署名をしました。" + vbLf +
            "(※注意:ブラウザのビルトインビューワの中には、署名が表示されないものがあります。)",
            tf, New PointF(72, 72))

        '' テスト証明書を初期化します。
        Dim pfxPath = Path.Combine("Resources", "Misc", "GcPdfTest.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 = "DioDocs for PDF サンプルブラウザ",
            .SignerName = "DioDocs",
            .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

        '' 2番目の署名フィールドを追加します。
        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