AcroForm サポート

概要

HotPDF v2.5.0 以降、ライブラリは PDF 1.7 ISO 32000-1 セクション 12.7 に準拠した対話型フォーム(AcroForm)を出力できます。各フォームフィールドは、フィールドディクショナリーと統合された Widget 注釈として作成され、ドキュメントに自動登録されます。そのため EndDoc でドキュメントが確定する時点で、グローバルな /AcroForm エントリーが Catalog に追加されます

対応しているフィールドタイプ

  • テキストフィールド(/FT /Tx)— THPDFPage.AddTextField で作成します。THPDFFormFieldFlags を通じて、単一行、複数行、パスワード、comb、ファイル選択、リッチテキスト、スクロール、スペルチェックの各オプションに対応します
  • チェックボックス(/FT /Btn、Pushbutton/Radio ビットなし)— THPDFPage.AddCheckBox で作成します。エクスポート値の名前と初期のチェック状態を設定できます
  • ラジオボタン(/FT /Btn /Ff Radio)— THPDFPage.AddRadioButton で作成します。同じグループ名で複数回呼び出すと、12.7.4.2 が要求するのと同じように、/Kids 配列を持つ共通の親フィールドの下に統合されます
  • コンボボックス(/FT /Ch /Ff Combo)— THPDFPage.AddComboBox で作成します。選択肢はオープン配列で渡します
  • リストボックス(/FT /Ch)— THPDFPage.AddListBox で作成します。ffMultiSelect で複数選択が有効になります
  • プッシュボタン(/FT /Btn /Ff Pushbutton)— THPDFPage.AddPushButton で作成します。キャプション(/MK /CA)は省略できます。HotPDF v2.31.0 以降では、THPDFPage.AddPushButtonWithAction がウィジェットに PDF アクションディクショナリーを取り付け、ボタンのクリックで /SubmitForm(フィールド値を URL に送信、PDF 1.2 12.7.5.2)、/ResetForm(PDF 1.2 12.7.5.3)、/JavaScript(JS スニペットを実行、PDF 1.3 12.6.4.16)、/URI(システムブラウザーで URL を開く、PDF 1.1 12.6.4.7)のいずれかを実行できます
  • 署名プレースホルダーフィールド(/FT /Sig)— HotPDF v2.12.0 以降で THPDFPage.AddSignatureField により作成できます。署名フィールドが 1 つでも存在すると、AcroForm ディクショナリーには自動的に /SigFlags 3(SignaturesExist + AppendOnly)が設定されます。フィールドは未署名のまま残るため、ファイル保存後に外部ツール(Adobe Acrobat、Foxit、専用の CMS / PKCS#7 署名ライブラリー)が実際の暗号署名を添付できます
  • インプレース署名ワークフロー — HotPDF v2.23.0 以降で、THPDFPage.AddSignedSignatureField + THotPDF.PreparePDFForSigning + THotPDF.InsertSignatureHex の組み合わせが使えます。最初の呼び出しで、/ByteRange と /Contents のプレースホルダーを備えた /V 署名ディクショナリーが確保されます。ドキュメントの保存後、ホストアプリケーションは PreparePDFForSigning を呼んで /ByteRange を書き換え、ハッシュ計算の対象となるファイル範囲を取得します。CMS / PKCS#7 の分離署名を外部で生成したら(Windows CryptoAPI、OpenSSL、専用の署名ライブラリーなど)、InsertSignatureHex を呼んでプレースホルダーに署名の 16 進文字列を書き込みます。ファイル内の他のバイトには一切触れません

作成時のフィールドラッパー

HotPDF v2.292.12 以降、THPDFPage.CreateTextField、CreateCheckBox、CreateRadioButton、CreateComboBox、CreateListBox の各ヘルパーは、既存の Add... メソッドと同じ AcroForm ウィジェットを作成し、その場で設定できる軽量な THPDFAcroFormField ラッパーを返します

HotPDF v2.292.26 以降、THotPDF.SetFormFieldTooltip はフィールド名を指定して PDF の /TU ユーザーヒントを設定します。対象は既存の Add... メソッドで作成したフィールドで、ラッパーレベルの THPDFAcroFormField.SetTooltip と同じワークフローです

HotPDF v2.298.0 以降、作成時のフィールド API と読み込み済みドキュメントのフィールド作成 API は、ルートフィールド名が重複していると、ウィジェットを登録する前に診断例外を発生させます。同じグループ名での AddRadioButton の繰り返し呼び出しは、1 つの親フィールドを共有して /Kids 配列の下に子ウィジェットを追加するだけなので、引き続き有効です

ラッパーは、/TU ツールチップ、共通のフィールドフラグ(SetReadOnly、SetRequired、SetNoExport)、/DA デフォルト外観文字列、/AA /K、/AA /F、/AA /V、/AA /C といったフィールドレベルの追加アクション、さらに THPDFActionBuilder によるウィジェットのマウス/フォーカスアクションについて、チェーン可能なセッターを公開しています

作成時ラッパーの Pascal 例

Field := HPDF.CurrentPage.CreateTextField('Email', '', Rect(50, 80, 250, 104));
Action := THPDFActionBuilder.JavaScript('event.rc = event.value.indexOf("@") > 0;');
try
  Field.SetTooltip('Email address');
  Field.SetRequired(True);
  Field.SetReadOnly(False);
  Field.SetAdditionalAction(fatValidate, Action);
finally
  Action.Free;
  Field.Free;
end;

読み込み済みフォームフィールドの検査と更新

HotPDF v2.121.9 以降、アプリケーションは THotPDF.LoadFromFile で既存の AcroForm PDF を読み込み、フィールドを列挙し、名前・型・値を参照し、フィールド値を変更し、読み取り専用フラグを切り替え、THotPDF.SaveLoadedDocument で読み込んだオブジェクトグラフを保存できます。この経路は、読み込み済みドキュメントへの永続的な編集を想定したものです。読み込んだフィールド値の変更を保存するためだけに BeginDoc / EndDoc を呼ぶことは避けてください

フィールドヘルパーは GetFormFieldCount、GetFormFieldName、GetFormFieldType、GetFormFieldValue、SetFormFieldValue、SetFormFieldReadOnly です。フィールドの検索には、0 始まりのフィールドインデックスと完全修飾フィールド名のどちらでも渡せます。THPDFLoadedFormFieldType の戻り値は lfftText、lfftButton、lfftChoice、lfftSignature、lfftUnknown のいずれかです

読み込みフィールドの Pascal 例

HPDF.LoadFromFile('InputForm.pdf');
for I := 0 to HPDF.GetFormFieldCount - 1 do
  Writeln(HPDF.GetFormFieldName(I), ' = ', HPDF.GetFormFieldValue(I));

HPDF.SetFormFieldValue('CustomerName', 'Bob');
HPDF.SetFormFieldValue('Plan', 'Premium');
HPDF.SetFormFieldReadOnly('CustomerName', True);
HPDF.SaveLoadedDocument('UpdatedForm.pdf');

フィールド追加アクション

AttachFieldKeyStrokeAction、AttachFieldFormatAction、AttachFieldValidateAction、AttachFieldCalculateAction の各ラッパーは、PDF の /K、/F、/V、/C トリガーに対応して、フィールドの /AA ディクショナリーへ JavaScript を取り付けます。同じトリガーで JavaScript、ResetForm、SubmitForm、URI、Hide、ImportData、チェーンされた /Next アクションといった再利用可能なアクションチェーンを実行したい場合は、SetFormFieldAdditionalAction かその名前付き THPDFActionBuilder ラッパーを使います。ウィジェットレベルのマウス/フォーカストリガーも、SetFormFieldAnnotationAction と名前付きマウス/フォーカスヘルパー経由でフィールド名を指定して取り付けられます。対応するクリアヘルパーは 1 つのトリガーだけを取り除き、/AA ディクショナリーの残りには触れません

外観の生成

既定では、出力される /AcroForm ディクショナリーは /NeedAppearances true を設定し、外観ストリームの描画を表示側のビューアー(Adobe Reader、Foxit、Chrome、各種ブラウザー、Apple Preview)に委ねます。フィールドを追加する前に THotPDF.AutoFormAppearances を true にすると、HotPDF はすべてのテキストフィールド、プッシュボタン、選択肢(コンボ/リスト)、さらに各チェックボックス/ラジオ子ウィジェットの Yes / Off 状態について、/AP /N フォーム XObject(PDF 1.7 8.10)を事前生成します。AcroForm ディクショナリーには /NeedAppearances false と、標準 14 基本フォント(Helv = Helvetica、ZaDb = ZapfDingbats)を参照する /DR デフォルトリソースエントリーが設定されるため、/NeedAppearances を無視するレンダラーでもフィールド内容を正しく描画できます。HotPDF v2.28.0 以降で利用可能です

フィールドフラグリファレンス(THPDFFormFieldFlags)

  • ffReadOnly、ffRequired、ffNoExport — すべてのフィールドタイプに共通する Table 227 のフラグです
  • ffMultiline、ffPassword、ffFileSelect、ffDoNotSpellCheck、ffDoNotScroll、ffComb、ffRichText — Tx 固有のフラグです(Table 228)
  • ffEdit、ffSort、ffMultiSelect、ffDoNotSpellCheck、ffCommitOnSelChange — Ch 固有のフラグです(Table 230)

Pascal 例

HPDF.BeginDoc;
HPDF.AddPage;
HPDF.CurrentPage.AddTextField('Name', '', Rect(50, 100, 250, 120));
HPDF.SetFormFieldTooltip('Name', 'Customer name');
HPDF.CurrentPage.AddCheckBox('Agree', 'Yes', Rect(50, 130, 70, 145), True);
HPDF.CurrentPage.AddRadioButton('Color', 'Red',   Rect(50, 160, 70, 175), True);
HPDF.CurrentPage.AddRadioButton('Color', 'Green', Rect(80, 160, 100, 175));
HPDF.CurrentPage.AddRadioButton('Color', 'Blue',  Rect(110, 160, 130, 175));
HPDF.CurrentPage.AddComboBox('Country', 'CN',
                             ['CN', 'US', 'JP'], Rect(50, 190, 250, 210));
HPDF.EndDoc;

制限事項

  • AutoFormAppearances の生成器が現在レイアウトできるのは、ASCII / WinAnsi で表現できる値だけです。/V にマルチバイト(UTF-8)テキストが入るフィールドでは、ホストビューアーが外観を再生成するまで、保存された /AP は空の矩形を描画します
  • Down(/D)と Rollover(/R)のサブ状態は生成されず、通常状態(/N)だけが出力されます
  • 新しい AcroForm ウィジェットを作成する際には、フィールド名のルートエントリー重複がチェックされます。ラジオ親/ウィジェットのパターンを超えた階層的な部分名の構築は、呼び出し側の責任のままです

関連項目