El Componente PDFium para Delphi y Lazarus intercambia datos de formularios y anotaciones a través de XFDF, el formato de intercambio XML definido por la norma ISO 19444-1. El método TPdf.ExportXFDF serializa cada valor de campo de formulario y cada anotación admitida en el documento cargado a un archivo XFDF o un objeto TStream; por su parte, TPdf.ImportXFDF lee un documento XFDF de vuelta, volviendo a crear las anotaciones en sus respectivas páginas y aplicando los valores de los campos. Ese único ciclo de ida y vuelta cubre dos flujos de trabajo que toda aplicación de documentos acaba requiriendo: que un revisor marque un PDF en Acrobat y le envíe los comentarios por correo para su fusión, o que una regla de cumplimiento exija que los datos de los formularios residan en un archivo independiente, auditable y sujeto a diferencias, en lugar de estar integrados en el propio PDF
¿Admite PDFium la importación y exportación de XFDF?
La biblioteca PDFium propiamente dicha no lo admite. La API nativa en C no dispone en absoluto de funciones XFDF o FDF (nada en sus cabeceras públicas lee o escribe ninguno de los dos formatos), por lo que ningún envoltorio (wrapper) le permitirá lograrlo. Por tanto, el Componente PDFium implementa todo el motor XFDF en Pascal, en una unidad dedicada que genera y analiza el XML directamente sobre el modelo de datos de anotaciones y campos de formulario TPdf existente. El escritor emite el XML manualmente y el lector es un analizador de máquina de estados escrito a mano, por lo que esta característica no añade ninguna dependencia de Delphi XMLDoc o de las unidades FPC DOM y se comporta de manera idéntica en Delphi y Lazarus
Esta elección de diseño resulta importante al evaluar alternativas. Si ha estado llamando a funciones básicas FPDF_* desde Pascal, XFDF representa un muro: esta capacidad simplemente no se encuentra en la DLL. El componente supera ese obstáculo tratando a XFDF como un simple problema de serialización: recopila los valores de los campos y los registros de anotación que el wrapper ya sabe cómo leer, los escribe como XML estándar y realiza el proceso inverso en la importación
¿Qué contiene un archivo XFDF?
La norma ISO 19444-1 define XFDF como la representación XML de FDF, y su contenido se divide en dos bloques de nivel superior. El elemento <fields> contiene los nombres jerárquicos de los campos de formulario y sus valores: todo lo que el usuario escribió, seleccionó o marcó en un AcroForm. El elemento <annots> contiene las anotaciones: TPdf.ExportXFDF emite 18 subtipos (text, highlight, underline, strikeout, squiggly, line, circle, square, caret, polygon, polyline, stamp, ink, freetext, fileattachment, sound, link y redact). Las anotaciones Widget se excluyen deliberadamente de <annots> porque sus datos viajan en <fields>, y los subtipos internos del visor, como Popup, no forman parte del vocabulario de XFDF
Para lograr que el ciclo de ida y vuelta sea fiel, el registro TPdfAnnotation se amplió con los metadatos que prevé XFDF: Name (el identificador único NM), Subject, ModificationDate, CreationDate, Icon, Opacity, extremos de línea, vértices de polígonos y polilíneas, y trazos de gestos de tinta. Cada nuevo campo se empareja con un centinela booleano Has*, por lo que el código que creaba anotaciones en versiones anteriores sigue compilándose y sigue produciendo los mismos diccionarios: un campo no establecido nunca se escribe. Si ya crea marcado mediante programación, el mismo registro que utiliza para las anotaciones de marcado de texto con puntos cuadrangulares contiene ahora todo lo que XFDF necesita
¿Cómo exportar datos de formularios y anotaciones a XFDF?
Una sola llamada procesa todo el documento. Cargue el PDF con el llenado de formularios activado, llame a ExportXFDF y el componente recorrerá cada página, recopilará los valores de los campos y las anotaciones y escribirá el XML. El valor de retorno es el número de bytes UTF-8 escritos, lo que representa una verificación rápida y útil en los registros
var
Pdf: TPdf;
Bytes: Integer;
begin
Pdf := TPdf.Create(Self);
Pdf.FormFill := True; // necesario para que los valores de los campos estén activos
Pdf.FileName := 'expense-report.pdf';
Pdf.Active := True;
Bytes := Pdf.ExportXFDF('expense-report.xfdf');
ShowMessage(Format('%d bytes of XFDF written', [Bytes]));
end;
Ambas direcciones tienen un overload de TStream, por lo que nada obliga a usar un archivo temporal en disco. Exportar a un TMemoryStream es la forma natural cuando el XFDF se dirige a una respuesta HTTP, a un blob de base de datos o a una entrada de archivo firmado
var
Buffer: TMemoryStream;
begin
Buffer := TMemoryStream.Create;
try
Pdf.ExportXFDF(Buffer); // mismo XML, sin archivo implicado
Buffer.Position := 0;
// pasar el flujo a una respuesta web, columna blob o entrada zip
finally
Buffer.Free;
end;
end;
¿Cómo fusiona ImportXFDF los comentarios de vuelta en el documento?
El lado de la importación es donde concluye el flujo de trabajo del revisor. Un colega anota el contrato en Acrobat, exporta los comentarios como XFDF y le envía unos pocos kilobytes de XML en lugar de una segunda copia del PDF. El método TPdf.ImportXFDF analiza ese archivo, crea cada anotación en la página que indica su atributo page y escribe los valores de los campos en las anotaciones widget correspondientes. La función devuelve la cantidad combinada de campos más anotaciones aplicadas, para que la interfaz de usuario pueda confirmar exactamente qué cantidad se ha recibido
var
Applied: Integer;
begin
Applied := Pdf.ImportXFDF('review-comments.xfdf');
StatusBar.SimpleText :=
Format('%d campos y anotaciones fusionados', [Applied]);
end;
El analizador es un escáner de etiquetas escrito a mano concebido bajo el principio de tolerancia en lugar de rigidez: se omiten los elementos desconocidos, se descartan las instrucciones de procesamiento, las declaraciones DOCTYPE y los comentarios, se descartan los nombres de indicadores no reconocidos y los valores de los atributos se decodifican mediante el conjunto completo de referencias a entidades XML y caracteres numéricos, incluyendo los pares sustitutos UTF-16. Los archivos XFDF producidos por Acrobat, por un visor web o por otra herramienta se fusionan sin problemas. Una vez que las anotaciones están en el documento, el ciclo de revisión continúa con los mecanismos de respuesta y estado descritos en la guía sobre la creación de un flujo de trabajo de revisión de anotaciones con el Componente PDFium, y los valores de campo importados participan en la lógica normal del orden de tabulación descrita en navegación por campos de formulario
¿Por qué son importantes los separadores decimales en XFDF?
Cada anotación en XFDF se posiciona mediante cadenas de coordenadas (como rect="70.5,540,200,560") y la norma ISO 19444-1 exige el uso del punto como separador decimal. El formateo de coma flotante por defecto de Delphi sigue la configuración regional de Windows, por lo que en un sistema alemán o francés, un simple FloatToStr convierte 70.5 en 70,5, lo que corrompe una lista de coordenadas separadas por comas en datos ilegibles que otros procesadores rechazan o interpretan mal. El Componente PDFium normaliza cada número que escribe: el separador decimal regional se sustituye por un punto y se recortan los ceros finales, por lo que el archivo exportado es idéntico a nivel de bytes tanto si se produjo en una máquina con configuración en-US como de-DE. Si alguna vez ha depurado una herramienta PDF que funcionaba en la oficina pero fallaba en el sitio de un cliente europeo, se habrá topado con esta categoría exacta de error; es útil saber que el componente se encarga de resolverlo por usted
¿Cuáles son los límites del viaje de ida y vuelta?
Vale la pena señalar dos límites claramente. En primer lugar, XFDF transporta datos de anotación, no apariencias renderizadas (los flujos de apariencia no forman parte del formato, por lo que el visor receptor regenera la apariencia de cada anotación a partir de sus propiedades). Un resaltado o un cuadrado se renderizará correctamente en todas partes; un sello con una apariencia personalizada recurrirá a lo que el visor de destino dibuje para el nombre de ese sello. En segundo lugar, la API PDFium subyacente dispone de configuradores para cadenas de texto, pero no para números de anotación o geometría de trazado, por lo que la opacidad (Opacity), los extremos de línea, los vértices y los gestos de tinta son de solo exportación: el componente los conserva fielmente al escribir XFDF, pero no los puede volver a grabar en un PDF al importar. Los valores de los campos, los contenidos, los colores, los rectángulos (rects), los puntos cuadrangulares (quad points), las fechas y los metadatos de identidad realizan el ciclo completo en ambas direcciones
Para comenzar de forma práctica, el ejemplo XfdfLab se incluye en los conjuntos de demostración para Delphi, C++Builder y Lazarus, y conecta ambas llamadas a botones sobre cualquier PDF que abra. La compatibilidad con XFDF está incluida en la versión actual del Componente PDFium, junto con las API de anotaciones y formularios sobre las que se fundamenta