Ir al contenido

Aplanar campos de formulario como contenido estático de página

Esta receta aplana un AcroForm interactivo. Dibuja, como gráficos ordinarios, el valor actual de cada campo en el flujo de contenido de la página y luego elimina el diccionario AcroForm. El resultado es un formulario no interactivo: una representación estática de los campos que se ve igual en cualquier entorno, incluso en un lector sin compatibilidad con formularios (ISO 32000-2 §12.7). La receta construye el formulario a partir de examples/30-form-fields.php y luego llama a flattenForms().

Ventana de terminal
composer require nextpdf/core:^3

El aplanado «imprime» cada widget en su página correspondiente. Los campos de texto se convierten en texto BT … Tj … ET. Las casillas de verificación y los botones de opción se convierten en trazados dibujados. Los campos de elección se representan con su elemento seleccionado. Los botones de comando se representan como un recuadro estático con aspecto de botón. Esto coincide con el modelo de la especificación para una apariencia definida estáticamente, usado cuando el contenido de los campos se conoce de antemano (ISO 32000-2 §12.7). Como los valores quedan incrustados, no se necesita el mecanismo obsoleto NeedAppearances.

El perfil es structural. El documento incluye un /ID en el tráiler, que el paso posterior normaliza antes de comparar dos ejecuciones.

NextPDF\Core\Concerns\HasFormFields::flattenForms(): static aplana todos los campos creados en el documento como contenido estático de la página y descarta el AcroForm. Si no hay campos presentes, no realiza ninguna acción. Internamente, delega el trabajo en NextPDF\Form\FormFlattener.

El formulario se crea con los constructores de campos. Para ver los pasos, consultar Construir y rellenar previamente un formulario PDF. Después, llamar a flattenForms() antes de 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";

El ejemplo completo siguiente construye un formulario de varias secciones a partir de examples/30-form-fields.php. Lo rellena previamente, lo aplana y escribe en NEXTPDF_COOKBOOK_OUTPUT para el arnés de pruebas.

<?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',
'email' => '[email protected]',
'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";

Salida esperada:

Wrote flattened registration form

La salida conserva los mismos valores, pero sin campos interactivos. Un lector sin compatibilidad con formularios lo muestra de la misma manera.

  • El aplanado es irreversible. Una vez que se llama a save(), los campos interactivos desaparecen. Conviene conservar el original sin aplanar por si hay que editar los valores más adelante.
  • Orden de las llamadas. Ejecutar flattenForms() después de crear los campos y antes de save(). Llamarlo sin campos no hace nada, lo que es seguro.
  • Los campos de firma no se aplanan. La apariencia de un campo /Sig se genera a partir de su CMS SignedData, no de un valor que pueda volver a representarse. Volver a rasterizarla crearía un gráfico «fantasma» estático que ya no coincide con ninguna firma verificable. Por esa razón, el aplanador omite los campos de firma a propósito. Aplanar el formulario antes de firmar, nunca después.
  • Valores marcados de la casilla de verificación. Una casilla de verificación muestra su marca de verificación cuando su valor es Yes/On/1/true. Un valor vacío o Off muestra solo el recuadro.
  • Fuente para el texto aplanado. El texto aplanado usa la fuente actual. Si no hay ninguna fuente establecida, se usa Helvetica como reserva. Para valores de campo en CJK o con fuentes personalizadas, configurar la fuente deseada antes de flattenForms().

El aplanado escala linealmente con la cantidad de campos. Por cada campo, añade un bloque de contenido acotado y luego elimina el objeto AcroForm. En formularios típicos, se mantiene holgadamente dentro del presupuesto de 1500 ms / 64 MB.

El aplanado hace que los valores de los campos no se puedan editar en los lectores normales. Es un cambio de presentación, no un control de acceso. Los valores permanecen visibles en el contenido de la página, y cualquier herramienta de texto puede extraerlos. No considerar el aplanado como una redacción ni como una protección de valores sensibles. Para la confidencialidad, usar Cifrar con permisos. También conviene leer la advertencia sobre la cooperación del lector que aparece allí, ya que los bits de permiso tampoco imponen restricciones de lectura. Nunca aplanar un documento firmado. Aplanar primero y firmar después.

DeclaraciónEspecificaciónCláusulareference_id
Un formulario aplanado es una representación no interactiva (estática) de los campos.ISO 32000-2§12.7
La apariencia del campo se define estáticamente cuando su contenido se conoce de antemano.ISO 32000-2§12.7
Las apariencias incrustadas hacen innecesaria la marca obsoleta NeedAppearances.ISO 32000-2§12.7

NextPDF produce la estructura estática descrita en las cláusulas citadas. No declara conformidad general con ISO 32000-2.