NoPassSetFormFields.cs
// 
// このコードは、DioDocs for PDF のサンプルの一部として提供されています。
// © MESCIUS inc. All rights reserved.
// 
using System;
using System.IO;
using System.Drawing;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Pdf.Security;
using GrapeCity.Documents.Pdf.AcroForms;
using GrapeCity.Documents.Pdf.Spec;
using DsPdfWeb.Demos.Common;

namespace DsPdfWeb.Demos
{
    // このサンプルでは、パスワードで保護されたPDFをパスワードを指定せずに読み込み、
    // フォームのテキストフィールドなどの値を変更する方法を紹介しています。
    // 変更したPDFは保存後、パスワードを指定して再度読み込み、PDFビューワにて表示しています。
    public class NoPassSetFormFields
    {
        public int CreatePDF(Stream stream)
        {
            using var fsSrc = File.OpenRead(Path.Combine("Resources", "PDFs", "FormFields-password-user.pdf"));
            // パスワードで保護されたPDFをパスワードを指定せずに読み込めるようDecryptionOptionsを設定します。
            var dopt = new DecryptionOptions() { ThrowExceptionIfInvalidPassword = false };
            var docSrc = new GcPdfDocument();
            docSrc.Load(fsSrc, dopt);

            // CheckBoxFieldの値を変更します。
            //
            // 注1:
            // 以下のように名前を使用してフィールドにアクセスすることはできません。
            //   doc.AcroForm.Fields["cbf1"];
            // なぜなら、パスワードで保護されたPDF内の文字列は暗号化されており、
            // パスワードを指定しなければアクセスできないからです。
            // インデックスを使用したフィールドへのアクセスが唯一の方法です。
            var cbf = (CheckBoxField)docSrc.AcroForm.Fields[0];
            cbf.Checked = true;

            // RadioButtonFieldの値を変更します。
            var rbf = (RadioButtonField)docSrc.AcroForm.Fields[1];
            var values = rbf.GetCheckedAppearanceStreamNames();
            rbf.Value = values[0];

            // TextFieldの値を変更し、現在の日時を設定します。
            var tf = (TextField)docSrc.AcroForm.Fields[2];
            // 注2:
            // TextFieldの値は文字列として設定されますが、パスワードで保護されたPDFでは、
            // パスワードを指定せずに文字列を扱うことはできません。
            // このような場合、PdfNameを使用して設定する方法を取ることはできますが、
            // この方法はPDF仕様に準拠していません。
            // ただ、少なくともAdobe Acrobatはこの方法に対応しています。
            tf.PdfValue = new PdfName(DateTime.Now.ToString());

            // CombTextFieldの値をランダムな文字列に変更します。
            var ctf = (CombTextField)docSrc.AcroForm.Fields[3];
            var val = Util.LoremIpsum(1, 1, 1, 2, 3);
            val = val.Substring(0, Math.Min(val.Length, 10));
            ctf.PdfValue = new PdfName(val);

            // 注3:パスワードで保護されたPDFをパスワードを指定せずに読み込んだ場合、
            // 外観ストリームを生成できないので、AcroFormのNeedAppearancesを設定して、
            // 不足している外観ストリームを生成するようにAcrobatに指示します。
            docSrc.AcroForm.Set(PdfName.Std.NeedAppearances, PdfBool.True);

            // デモサイト限定の処理:
            // 変更後のパスワードで保護されたドキュメントを一時ファイルに保存し、
            // それをパスワードを指定して再度読み込むことで、PDFビューワにて
            // パスワードを入力せずに表示できるようにします。
            var fn = Path.GetTempFileName();
            {
                docSrc.Save(fn);
                var doc = new GcPdfDocument();
                using var fs = File.OpenRead(fn);
                doc.Load(fs, "user");
                doc.Save(stream);
            }
            File.Delete(fn);
            return docSrc.Pages.Count;
        }
    }
}