Dois formulários podem conter os mesmos campos e comportar-se de formas completamente diferentes. Um AcroForm mantém os seus campos como objetos PDF normais sobrepostos ao conteúdo real da página, pelo que qualquer leitor compatível consegue renderizá-lo. Um formulário XFA dinâmico quase nada mantém como PDF: os campos, o layout e até a geometria da página residem num pacote XML, e as páginas visíveis são geradas no momento da abertura por um motor de layout que apenas a Adobe distribuiu de forma generalizada. Se submeter esse ficheiro a um visualizador web, a um renderizador de arquivos ou a um extrator de texto, não obterá o formulário. O que obtém é uma única página cinzenta que diz "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." Qualquer pessoa que já tenha lidado com documentação governamental ou de seguros conhece essa página à primeira vista.
Esta mensagem de marcador de posição (placeholder) não representa um ficheiro corrompido. É exatamente o que o formato especifica que deve ocorrer quando nenhum processador XFA está presente e, a partir de 2026, isso descreve quase todos os visualizadores à exceção da versão desktop do Acrobat. Assim, a abordagem prática consiste em converter o formulário dinâmico num AcroForm simples antes de este chegar a qualquer etapa posterior do fluxo de trabalho. O HotPDF, a biblioteca de PDF da losLab para Delphi e C++Builder, realiza essa conversão no código, reconstruindo o formulário XML como campos nativos em páginas nativas.
Por que razão os dois modelos não podem coexistir
O AcroForm está definido na norma ISO 32000-1 §12.7. Cada campo é um objeto PDF com uma anotação de widget e um fluxo de aparência (appearance stream), a página é conteúdo PDF real e os dados sobrepõem-se a ela. O XFA inverte esta lógica: o formulário é um documento XML, um pacote XDP armazenado na entrada /XFA do dicionário AcroForm, e as páginas PDF de um formulário dinâmico contêm o marcador "Please wait" e nada mais, porque o conteúdo real nunca foi serializado como PDF. Um leitor processa o ficheiro de acordo com um ou outro modelo. Ignore a entrada /XFA e verá apenas a estrutura vazia; respeite-a sem ter um motor XFA e verá o aviso. A norma ISO 32000-2 encerrou este debate ao remover o XFA do PDF 2.0, sendo este o principal motivo pelo qual "converter enquanto ainda é possível" passou de uma situação excecional para uma política de receção de rotina.
Antes de efetuar qualquer conversão, classifique o ficheiro, pois nem todos os ficheiros XFA exibem a mensagem de aviso. Os formulários XFA estáticos contêm páginas PDF pré-renderizadas ao lado do XML, pelo que são visualizados em qualquer lado e apenas apresentam problemas quando preenchidos. Os formulários dinâmicos trazem apenas a página de aviso e são inutilizáveis até serem convertidos. Deve confiar apenas no próprio documento, nunca na extensão ou no remetente. Um ficheiro que renderiza conteúdo real num visualizador que não seja da Adobe mas que ainda contém uma entrada /XFA é estático ou híbrido; um ficheiro que mostra a página de aviso é dinâmico. Registe a categoria em que cada ficheiro de entrada se enquadra. Os dois tipos falham de formas diferentes no futuro, e um incidente sobre um formulário arquivado em branco resolve-se em segundos quando o registo de entrada já indica "XFA dinâmico, convertido, 47 campos mapeados, 2 avisos".
Converter um documento XFA carregado em campos nativos
A conversão é executada sobre um documento que já se encontra na memória. O FlattenLoadedXFA analisa o modelo XFA e os seus pacotes de dados, desenha o layout do formulário e reconstrói-o como campos AcroForm em páginas PDF reais:
var
Pdf: THotPDF;
MappedCount, I: Integer;
Warnings: TStrings;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.LoadFromFile('dynamic_xfa.pdf');
MappedCount := Pdf.FlattenLoadedXFA(True); // True = fields stay editable
Warnings := Pdf.XFAFlattenWarnings;
for I := 0 to Warnings.Count - 1 do
Log('XFA flatten warning: ' + Warnings[I]); // unmapped elements
Pdf.SaveLoadedDocument('native_acroform.pdf');
Log(Format('Mapped %d fields', [MappedCount]));
finally
Pdf.Free;
end;
end;
O valor de retorno e a lista de avisos constituem outputs e não ruído de depuração, pelo que deve reter ambos. A conversão perde informação por natureza: scripts XFA, campos calculados e comportamento de subformulários dinâmicos não têm equivalente em AcroForm, e o XFAFlattenWarnings identifica todos os elementos do modelo que não foram mapeados. Se arquivar o ficheiro convertido sem a respetiva lista de avisos, poderá mais tarde deparar-se com uma caixa de totais vazia numa cópia arquivada sem qualquer registo do motivo. A opção Editable controla se os novos campos continuam a poder ser preenchidos. Passe True se os utilizadores forem continuar a trabalhar com o formulário e bloqueie os valores quando o objetivo for obter um registo imutável.
A verificação da conversão é em parte visual e em parte estrutural, sendo necessárias ambas as abordagens. A vertente estrutural é simples: confirme se a contagem de campos corresponde ao MappedCount. A parte visual é aquela que deteta problemas reais. Abra o formulário de origem na versão desktop do Acrobat, que continua a ser o único visualizador com suporte para o motor XFA, lado a lado com o ficheiro convertido num leitor comum, e compare os valores e o layout em pelo menos uma amostra preenchida por modelo. Uma data que o motor XFA exibia como 2026-06-11 pode surgir na cópia AcroForm como um valor bruto sem formatação, e apenas o controlo visual detetará essa diferença.
Quando o input é um pacote XDP
Nem todos os processos começam a partir de um PDF preenchido. Por vezes, recebe o pacote XDP isoladamente, exportado de uma ferramenta de desenho de formulários ou fornecido por um sistema parceiro. O ApplyXFAAsAcroForm elimina a etapa de carregamento e aplica o pacote diretamente ao documento atual:
XDPBytes := TFile.ReadAllBytes('benefit-claim.xdp');
MappedCount := Pdf.ApplyXFAAsAcroForm(XDPBytes, True);
O mesmo grupo de chamadas também funciona no sentido inverso, para o caso menos frequente em que necessita de emitir XFA em vez de o consumir. O AddXFAPacket anexa pacotes individuais com nome, como 'xdp' ou 'config'. O SetXFADocument instala um payload completo de fluxo único numa única chamada. O ClearXFAPackets limpa o registo para que possa recomeçar, e o AddXFASignaturePacket incorpora elementos XAdES para fluxos de trabalho que assinam diretamente os dados do formulário XML. Produzir XFA em 2026 é uma necessidade muito específica, quase sempre motivada por um integrador antigo que rejeita qualquer outra alternativa, mas quando um contrato o exige, estas chamadas reduzem a tarefa a uma simples opção de configuração em vez de exigir uma ferramenta separada.
O outro significado de "achatamento" (flattening)
A palavra "achatamento" gera frequentemente equívocos nas conversações, uma vez que designa um processo totalmente diferente: fundir as aparências dos campos AcroForm no fluxo de conteúdo da página até que não restem quaisquer objetos interativos. O HotPDF não possui atualmente uma API dedicada a esse processo, e convém saber isto agora em vez de a meio de um projeto. O que a biblioteca oferece, em contrapartida, é o bloqueio ao nível do campo aquando da sua criação, complementado pelas permissões do documento:
// Lock the value at field creation: read-only text field
Pdf.CurrentPage.AddTextField('CaseNumber', 'BC-2026-0117',
Rect(50, 700, 220, 720), 0, [ffReadOnly]);
// Belt and suspenders: restrict form filling document-wide
Pdf.ActivateProtection := True;
Pdf.CryptKeyLength := aes256;
Pdf.OwnerPassword := 'records-owner';
Pdf.ProtectOptions := [prPrint, prInformationCopy, prExtractContent];
// fill permission withheld: prFillAnnotations is absent from the set
Tenha clareza sobre o que esta abordagem oferece e o que não oferece. Um campo apenas de leitura continua a ser um objeto de formulário. Ele surge no painel de campos do visualizador, o seu valor pode ser lido através da API do formulário e qualquer ferramenta que reescreva o ficheiro pode remover o indicador de apenas de leitura. Os parâmetros de permissão elevam o nível de segurança, mas dependem de o visualizador optar por os respeitar, uma limitação descrita de forma clara na norma ISO 32000-1. Quando um regulador exige que um documento arquivado não contenha quaisquer objetos de formulário, a solução transparente com o HotPDF passa por reconstruir o documento: ler os valores e desenhá-los como conteúdo normal com TextOut numa nova página, em vez de disfarçar indicadores de apenas leitura como achatamento. Um aspeto a reter na definição de permissões é que o CryptKeyLength tem de ser definido antes do BeginDoc; o resto está detalhado no nosso artigo sobre encriptação AES-256 e permissões.
O que o XFA representa para a conformidade de arquivo
As normas PDF/A e PDF/X rejeitam o XFA de forma categórica. Um fluxo de trabalho que alimente um arquivo em conformidade com a norma ISO 19005 tem, por isso, de efetuar primeiro a conversão, e a ordem não é negociável: carregar, FlattenLoadedXFA, guardar e, em seguida, executar a geração ou validação para fins de arquivo no AcroForm resultante. Não assuma a conversão como prova de conformidade. Ela corrige o modelo do formulário mas mantém os tipos de letra, as cores e os metadados tal como estavam originalmente, pelo que deve validar o output com o veraPDF antes de o considerar conforme. Assim que o formulário estiver estruturado em AcroForm, o seu comportamento passa a dispor de controlos específicos. Gatilhos de JavaScript, ações de submissão e scripts de validação são descritos no artigo sobre ações e campos AcroForm no HotPDF.
As APIs de registo, conversão e formulários XFA demonstradas aqui integram o HotPDF Component para Delphi e C++Builder, cuja documentação acompanha a evolução do suporte de funcionalidades XFA ao longo das versões recentes.