Artículo técnico

Convertir XFA a AcroForm en Delphi con HotPDF

Dos formularios pueden llevar los mismos campos y no comportarse en nada igual. Un AcroForm conserva sus campos como objetos PDF corrientes situados sobre contenido de página real, así que cualquier lector conforme lo dibuja. Un formulario XFA dinámico casi no conserva nada como PDF: los campos, la maquetación e incluso la geometría de página viven en un paquete XML, y las páginas visibles las produce al abrir un motor de composición que solo Adobe distribuyó de forma amplia. Dele ese archivo a un visor web, a un renderizador de archivo histórico o a un extractor de texto y no obtendrá el formulario. Obtendrá una única página gris que dice «Please wait... If this message is not eventually replaced by the proper contents of the document, your PDF viewer may not be able to display this type of document.». Cualquiera que haya ingerido papeleo público o de seguros reconoce esa página al instante

El marcador de posición no es corrupción. Es exactamente lo que el formato especifica que debe ocurrir cuando no hay ningún procesador XFA presente, y en 2026 eso describe a casi todos los visores fuera de Acrobat de escritorio. Así que la jugada práctica es convertir el formulario dinámico en un AcroForm sencillo antes de que llegue a nada aguas abajo. HotPDF, la biblioteca PDF de losLab para Delphi y C++Builder, hace esa conversión por código y reconstruye el formulario XML como campos nativos sobre páginas nativas

HotPDF: comparación lado a lado de un AcroForm, cuyas páginas, widgets y valores viven todos en el PDF, y un formulario XFA dinámico que muestra una página de marcador de posición sin motor XFA
AcroForm mantiene páginas, widgets y valores dentro del PDF para que cualquier lector dibuje el formulario, mientras que el XFA dinámico los esconde tras el marcador de posición de espera

Por qué los dos modelos no pueden convivir

AcroForm está definido en ISO 32000-1 §12.7. Cada campo es un objeto PDF con una anotación de widget y un flujo de apariencia, la página es contenido PDF genuino y los datos viajan encima. XFA invierte eso: el formulario es un documento XML, un paquete XDP guardado en la entrada /XFA del diccionario AcroForm, y las páginas PDF de un formulario dinámico contienen el marcador de posición de espera y nada más, porque el contenido real nunca se serializó como PDF. Un lector procesa un archivo con un modelo o con el otro. Ignore la entrada /XFA y verá el cascarón vacío; hónrela sin un motor XFA y verá el aviso. ISO 32000-2 zanjó el debate eliminando XFA de PDF 2.0, que es la razón principal de que «convertir mientras aún podemos» pasara de caso raro a política rutinaria de admisión

Antes de convertir nada, clasifíquelo, porque no todo archivo XFA muestra el marcador de posición. Los formularios XFA estáticos incluyen páginas PDF ya compuestas junto al XML, así que se ven en todas partes y solo se portan mal al rellenarlos. Los dinámicos incluyen únicamente el marcador de posición y son inservibles hasta convertirlos. Lo que hay que creer es el documento, nunca la extensión ni el remitente. Un archivo que muestra contenido real en un visor que no es de Adobe y aun así lleva una entrada /XFA es estático o híbrido; un archivo que enseña la página de aviso es dinámico. Anote en qué cubo cayó cada archivo de admisión. Los dos tipos se rompen de maneras distintas más adelante, y un ticket sobre un formulario archivado en blanco se cierra en segundos cuando el registro de admisión ya dice «XFA dinámico, convertido, 47 campos asignados, 2 avisos»

Flujo de clasificación en admisión de documentos XFA en Delphi: los archivos que muestran contenido real fuera de Acrobat son estáticos o híbridos, mientras que los que enseñan la página de espera son dinámicos y hay que convertirlos
Los formularios híbridos se delatan al mostrar contenido real en visores que no son de Adobe, mientras que los dinámicos se revelan solo por la página de marcador de posición

Convertir un documento XFA cargado en campos nativos

La conversión se ejecuta sobre un documento que ya está en memoria. FlattenLoadedXFA analiza la plantilla XFA y sus paquetes de datos, compone el formulario y lo reconstruye como campos AcroForm sobre páginas PDF reales:

var
  Pdf: THotPDF;
  MappedCount, I: Integer;
  Warnings: TStrings;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.LoadFromFile('dynamic_xfa.pdf');
    MappedCount := Pdf.FlattenLoadedXFA(True);   // True = los campos siguen editables
    Warnings := Pdf.XFAFlattenWarnings;
    for I := 0 to Warnings.Count - 1 do
      Log('XFA flatten warning: ' + Warnings[I]); // elementos sin asignar
    Pdf.SaveLoadedDocument('native_acroform.pdf');
    Log(Format('Mapped %d fields', [MappedCount]));
  finally
    Pdf.Free;
  end;
end;

El valor devuelto y la lista de avisos son salida, no ruido de depuración, así que conserve ambos. La conversión pierde información por naturaleza: el scripting XFA, los campos calculados y el comportamiento de los subformularios dinámicos no tienen equivalente en AcroForm, y XFAFlattenWarnings nombra cada elemento de plantilla que no se pudo asignar. Archive el archivo convertido sin su lista de avisos y algún día se quedará mirando una casilla de totales vacía en una copia archivada sin ningún registro del porqué. El indicador Editable controla si los campos nuevos siguen siendo rellenables. Pase True cuando la gente vaya a seguir trabajando con el formulario después, y fije los valores cuando el objetivo sea un registro congelado

Cadena de HotPDF que convierte un documento XFA dinámico cargado en campos AcroForm editables en Delphi y saca a la luz el scripting y los campos calculados sin asignar mediante XFAFlattenWarnings
FlattenLoadedXFA analiza y vuelca los paquetes XDP en campos AcroForm editables, y XFAFlattenWarnings registra cada elemento que no se pudo asignar

Comprobar una conversión es en parte visual y en parte estructural, y necesita las dos mitades. La estructural es fácil: confirme que el recuento de campos coincide con MappedCount. La visual es la que atrapa el daño real. Abra el formulario de origen en Acrobat de escritorio, todavía el único visor que ejecuta el motor XFA, junto al archivo convertido en un lector corriente, y compare valores y maquetación en al menos una muestra rellenada por plantilla. Una fecha que el motor XFA mostraba como 2026-06-11 puede aterrizar en la copia AcroForm como un valor crudo sin formato, y eso solo lo pillan sus ojos

Cuando la entrada es un paquete XDP

No todo trabajo parte de un PDF ya poblado. A veces recibe el paquete XDP por su cuenta, exportado de una herramienta de diseño de formularios o entregado por un sistema socio. ApplyXFAAsAcroForm se salta el paso de carga y aplica el paquete directamente al documento actual:

XDPBytes := TFile.ReadAllBytes('benefit-claim.xdp');
MappedCount := Pdf.ApplyXFAAsAcroForm(XDPBytes, True);

El mismo grupo de llamadas funciona también en el sentido contrario, para el caso más raro en que tiene que emitir XFA en vez de consumirlo. AddXFAPacket adjunta paquetes con nombre concretos, como 'xdp' o 'config'. SetXFADocument instala en una sola llamada una carga completa de flujo único. ClearXFAPackets borra el registro para poder empezar de nuevo, y AddXFASignaturePacket incrusta material XAdES para flujos que firman directamente los datos XML del formulario. Producir XFA en 2026 es una necesidad de nicho, casi siempre forzada por un consumidor heredado que no acepta otra cosa, pero cuando un contrato lo exige estas llamadas lo dejan en una decisión de configuración en vez de en una herramienta aparte

El otro significado de «aplanar»

La palabra «aplanar» hace tropezar muchas conversaciones, porque nombra una segunda operación completamente distinta: quemar las apariencias de los campos AcroForm en el flujo de contenido de la página hasta que no quede ningún objeto interactivo. HotPDF no tiene hoy ninguna API para eso, y conviene saberlo ahora y no a mitad de un proyecto. Lo que la biblioteca le da a cambio es bloqueo a nivel de campo en el momento de crearlo, respaldado por los permisos del documento:

// Bloquee el valor al crear el campo: campo de texto de solo lectura
Pdf.CurrentPage.AddTextField('CaseNumber', 'BC-2026-0117',
  Rect(50, 700, 220, 720), 0, [ffReadOnly]);

// Cinturón y tirantes: restrinja el relleno en todo el documento
Pdf.ActivateProtection := True;
Pdf.CryptKeyLength := aes256;
Pdf.OwnerPassword := 'records-owner';
Pdf.ProtectOptions := [prPrint, prInformationCopy, prExtractContent];
// permiso de relleno retenido: prFillAnnotations no está en el conjunto

Tenga claro qué le compra eso y qué no. Un campo de solo lectura sigue siendo un objeto de formulario. Aparece en el panel de campos del visor, su valor se puede leer por la API de formularios, y una herramienta que reescriba el archivo puede volver a quitar el indicador de solo lectura. Los indicadores de permisos suben el listón pero dependen de que el visor decida respetarlos, una limitación que ISO 32000-1 enuncia sin rodeos. Cuando un regulador insiste en que un registro archivado no contenga objeto de formulario alguno, la respuesta honesta con HotPDF hoy es reconstruir el documento: extraiga los valores y dibújelos como contenido TextOut corriente en una página nueva, en lugar de disfrazar de aplanado unos indicadores de solo lectura. Algo que recordar por la vía de los permisos es que CryptKeyLength hay que fijarlo antes de BeginDoc; el resto está en nuestro artículo sobre cifrado AES-256 y permisos

Qué implica XFA para la conformidad de archivado

PDF/A y PDF/X rechazan XFA de plano. Por tanto, una cadena que alimente un archivo ISO 19005 tiene que convertir primero, y el orden no es negociable: cargar, FlattenLoadedXFA, guardar y después ejecutar la generación o la validación de archivado sobre el resultado AcroForm. No tome la conversión por prueba de conformidad. Arregla el modelo de formulario y deja fuentes, color y metadatos exactamente como estaban, así que valide la salida con veraPDF antes de fiarse de ella. Una vez el formulario está del lado AcroForm, su comportamiento tiene su propio juego de controles. Los disparadores de JavaScript, las acciones de envío y los scripts de validación se tratan en el artículo sobre campos y acciones de AcroForm en HotPDF

El registro XFA, la conversión y las API de formularios mostradas aquí se distribuyen con el HotPDF Delphi Component para Delphi y C++Builder, cuya documentación sigue el conjunto de funciones XFA a medida que ha crecido en las últimas versiones