将表单字段扁平化为静态页面内容
要点速览
标题为“要点速览”的章节本示例会将一份交互式 AcroForm 扁平化。它会把每个字段的当前值作为普通图形绘制到页面内容流中,随后移除 AcroForm 字典。结果是一份非交互式表单:字段以静态形式呈现,在任何环境中看起来都一致,即使阅读器不支持表单也是如此(ISO 32000-2 §12.7)。本示例先从 examples/30-form-fields.php 构建表单,再调用 flattenForms()。
composer require nextpdf/core:^3概念总览
标题为“概念总览”的章节扁平化会把每个部件「打印」到其所在页面上。文本字段会变成 BT … Tj … ET 文本。复选框与单选按钮会变成绘制出的路径。选择字段会绘制出已选中的项目。命令按钮会绘制成一个静态的、类似按钮的方框。这符合规范中静态定义外观的模型,也就是字段内容事先已知时采用的做法(ISO 32000-2 §12.7)。由于这些值已经写入内容,就不需要已弃用的 NeedAppearances 机制。
此配置文件为 structural。文档带有尾部 /ID,后处理流程会在比较两次运行结果之前先将其规范化。
API 接口
标题为“API 接口”的章节NextPDF\Core\Concerns\HasFormFields::flattenForms(): static 会把文档中创建的每个字段扁平化为静态页面内容,并移除 AcroForm。若没有任何字段,它不会执行任何操作。在内部,它会将这项工作委托给 NextPDF\Form\FormFlattener。
使用字段构造函数构建表单。相关步骤请参阅 构建并预填 PDF 表单一节。随后调用 flattenForms(),并确保在 save() 之前完成。
代码示例 — 快速上手
标题为“代码示例 — 快速上手”的章节<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Flattened Form');$doc->addPage();
$doc->textField(name: 'full_name', x: 20, y: 30, w: 90, h: 8, default: 'Ada Lovelace');$doc->checkBox(name: 'agree', x: 20, y: 45, size: 5, checked: true);
// Bake the field values into the page; the AcroForm is removed.$doc->flattenForms();
$doc->save(__DIR__ . '/flattened.pdf');echo "Wrote flattened.pdf (no interactive fields)\n";代码示例 — 生产环境
标题为“代码示例 — 生产环境”的章节下方的完整示例会从 examples/30-form-fields.php 构建这份多区段表单。它会先预填表单,接着将其扁平化,并写入 NEXTPDF_COOKBOOK_OUTPUT 供测试工具使用。
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();$doc->setTitle('Customer Registration — Flattened');$doc->addPage();
$doc->setFont('helvetica', 'B', 20);$doc->cell(0, 14, 'Customer Registration (read-only copy)', newLine: true);$doc->ln(4);
$leftMargin = 15.0;$fieldX = 70.0;$fieldW = 120.0;$fieldH = 8.0;$rowSpacing = 12.0;
$prefill = [ 'full_name' => 'Ada Lovelace', 'phone' => '+44 20 7946 0000', 'company' => 'Analytical Engines Ltd',];
$y = 40.0;$doc->setFont('helvetica', '', 10);foreach ($prefill as $name => $value) { $doc->setXY($leftMargin, $y); $doc->cell(50, $fieldH, ucwords(str_replace('_', ' ', $name)) . ':'); $doc->textField(name: $name, x: $fieldX, y: $y, w: $fieldW, h: $fieldH, default: $value); $y += $rowSpacing;}
$y += 6;$doc->setXY($leftMargin, $y);$doc->cell(0, 7, 'Newsletter');$doc->checkBox(name: 'newsletter', x: $leftMargin + 70, y: $y, size: 5, checked: true);
// Flatten: widgets become static page content; the AcroForm is dropped.$doc->flattenForms();
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');$doc->save($out !== false ? $out : __DIR__ . '/registration-flattened.pdf');
echo "Wrote flattened registration form\n";预期输出:
Wrote flattened registration form输出会显示相同的值,但不再包含交互式字段。不支持表单的阅读器也会以相同方式绘制它。
边缘情况与陷阱
标题为“边缘情况与陷阱”的章节- 扁平化不可逆。 一旦你调用
save(),交互式字段就会消失。如果之后可能还需要编辑这些值,请保留未扁平化的原始文件。 - 调用顺序。 请在创建字段之后运行
flattenForms(),也就是在save()之前。在没有字段时调用它不会执行任何操作,这是安全的。 - 签名字段不会被扁平化。
/Sig字段的视觉表面来自其 CMS SignedData 生成的外观,而不是可重新渲染的值。重新栅格化它会产生一个静态的「残影」图形,不再对应任何可验证的签名。因此,扁平化流程会刻意跳过签名字段。请务必在签名之前扁平化表单,绝不要在签名之后。 - 复选框的真值判断。 当复选框的值为
Yes/On/1/true时,它会绘制勾选标记。空值或Off值则只会绘制方框。 - 扁平化文本所用的字体。 扁平化后的文本会使用当前字体。若未设置字体,它会回退使用 Helvetica。若字段值是 CJK 或使用自定义字体,请在
flattenForms()之前设置你想使用的字体。
扁平化的开销会随字段数量呈线性增长。对每个字段,它会追加一个有界的内容块,接着移除 AcroForm 对象。对于一般表单,它会稳定控制在 1500 ms/64 MB 的预算之内。
安全性注意事项
标题为“安全性注意事项”的章节扁平化会让字段值在常规阅读器中无法编辑。这是呈现方式的改变,并非访问控制。这些值仍会显示在页面内容中,任何文本工具都能提取它们。请勿把扁平化当成遮蔽(redaction),也不要当成敏感值的保护手段。若需要机密性,请使用 用权限加密一节。也请一并阅读该节中关于阅读器需配合(reader-cooperative)的提醒,因为权限位同样无法强制执行读取限制。绝不要扁平化一份已签名的文档。请先扁平化,再签名。
符合性
标题为“符合性”的章节| 陈述 | 规范 | 条款 | 参考 ID |
|---|---|---|---|
| 扁平化表单是字段的非交互式(静态)呈现。 | ISO 32000-2 | §12.7 | |
| 当字段内容事先已知时,其外观为静态定义。 | ISO 32000-2 | §12.7 | |
由于外观已被写入内容中,已弃用的 NeedAppearances 标志就变得不必要。 | ISO 32000-2 | §12.7 |
NextPDF 会生成所引条款描述的静态结构。它并未主张全面符合 ISO 32000-2。