Teknisk artikel

Fladgørelse af XFA til AcroForm i Delphi med HotPDF

To formularer kan indeholde de samme felter og alligevel opføre sig vidt forskelligt. En AcroForm beholder sine felter som almindelige PDF-objekter, der ligger oven på det rigtige sideindhold, så enhver kompatibel fremviser kan tegne den. En dynamisk XFA-formular gemmer næsten intet som PDF: Felterne, layoutet og endda sidegeometrien lever i en XML-pakke, og de synlige sider produceres ved åbning af en layoutmotor, som kun Adobe for alvor har udbredt. Hvis du sender den fil til en webfremviser, en arkiv-renderer eller en tekstekstraktor, får du ikke formularen. Du får en enkelt grå side med teksten "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." Enhver, der har arbejdet med offentlige dokumenter eller forsikringspapirer, kender den side med det samme

Pladsholderen er ikke en beskadigelse af filen. Det er præcis, hvad formatet angiver skal ske, når der ikke er nogen XFA-processor til stede, hvilket i dag beskriver næsten enhver fremviser udover desktop-Acrobat. Det mest praktiske er derfor at konvertere den dynamiske formular til en almindelig AcroForm, før den når de efterfølgende systemer. HotPDF, PDF-biblioteket til Delphi og C++Builder fra losLab, udfører denne konvertering i kode og genopbygger XML-formularen som oprindelige felter på oprindelige sider

Hvorfor de to modeller ikke kan eksistere side om side

AcroForm er defineret i ISO 32000-1 §12.7. Hvert felt er et PDF-objekt med en widget-annotering og en udseendestrøm (appearance stream), siden er ægte PDF-indhold, og dataene ligger oven på det. XFA vender dette om: Formularen er et XML-dokument, en XDP-pakke gemt i /XFA-posten i AcroForm-ordbogen, og en dynamisk formulars PDF-sider indeholder kun pladsholderen "Please wait" og intet andet, fordi det reelle indhold aldrig blev serialiseret som PDF. En læser behandler filen ud fra den ene eller den anden model. Ignorerer du /XFA-posten, ser du den tomme skal; respekterer du den uden en XFA-motor, ser du advarslen. ISO 32000-2 afsluttede debatten ved at fjerne XFA fra PDF 2.0, hvilket er hovedårsagen til, at "konverter mens vi stadig kan" er gået fra at være et særtilfælde til en fast rutine ved modtagelse af filer

Før du konverterer noget som helst, bør du klassificere det, da det ikke er alle XFA-filer, der viser pladsholderen. Statiske XFA-formularer leveres med præ-renderede PDF-sider ved siden af XML-koden, så de kan vises overalt og kun opfører sig forkert, når de udfyldes. Dynamiske formularer leveres udelukkende med pladsholderen og er ubrugelige, indtil de konverteres. Det eneste, du kan stole på, er dokumentet, aldrig filendelsen eller afsenderen. En fil, der renderer rigtigt indhold i en ikke-Adobe-fremviser, men stadig indeholder en /XFA-post, er statisk eller hybrid; en fil, der viser advarselssiden, er dynamisk. Registrer, hvilken kategori hver modtaget fil lander i. De to typer fejler på forskellige måder senere, og en sag om en tom arkiveret formular kan lukkes på få sekunder, hvis modtagelsesloggen allerede siger "dynamisk XFA, konverteret, 47 felter tilknyttet, 2 advarsler"

Konvertering af et indlæst XFA-dokument til oprindelige felter

Konverteringen kører mod et dokument, der allerede er indlæst i hukommelsen. FlattenLoadedXFA parser XFA-skabelonen og dens datapakker, layouter formularen og genopbygger den som AcroForm-felter på rigtige PDF-sider:

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;

Returværdien og advarselslisten er vigtige output og ikke blot fejlfindingsstøj, så gem begge dele. Konvertering mister af natur oplysninger: XFA-scripting, beregnede felter og underformular-adfærd har ingen modpart i AcroForm, og XFAFlattenWarnings navngiver ethvert skabelonelement, der ikke kunne tilknyttes. Hvis du arkiverer den konverterede fil uden advarselslisten, kan du en dag risikere at stå med et tomt totalfelt i en arkiveret kopi uden nogen registrering af hvorfor. Flaget Editable styrer, om de nye felter forbliver redigerbare. Send True, hvis der skal arbejdes videre med formularen bagefter, og lås værdierne fast, hvis målet er en uforanderlig registrering

Kontrol af en konvertering er dels visuel, dels strukturel, og du har brug for begge dele. Den strukturelle del er nem: bekræft, at feltantallet matcher MappedCount. Den visuelle del er den, der fanger reelle fejl. Åbn kildeformularen i desktop-Acrobat, som stadig er den eneste fremviser, der kører XFA-motoren, ved siden af den konverterede fil i en almindelig læser, og sammenlign værdier og layout på mindst én udfyldt prøve pr. skabelon. En dato, som XFA-motoren viste som 2026-06-11 kan lande i AcroForm-kopien som en rå, uformateret værdi, og det er kun dine øjne, der vil opdage det

Når inputtet er en XDP-pakke

Ikke alle opgaver starter fra en udfyldt PDF. Nogle gange modtager du XDP-pakken for sig selv, eksporteret fra et formulardesignværktøj eller overdraget fra et partnersystem. ApplyXFAAsAcroForm udelader indlæsningstrinnet og anvender pakken direkte på det aktuelle dokument:

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

Den samme gruppe af kald kan også køre i den anden retning til de mere sjældne tilfælde, hvor du skal generere XFA frem for at modtage det. AddXFAPacket tilknytter individuelle navngivne pakker såsom 'xdp' eller 'config'. SetXFADocument installerer en komplet enkeltstrøm-payload i ét kald. ClearXFAPackets sletter registreringen, så du kan starte forfra, og AddXFASignaturePacket indlejrer XAdES-materiale til arbejdsgange, der underskriver XML-formulardataene direkte. Generering af XFA er et nichebehov, næsten altid fremtvunget af et enkelt forældet system, der nægter at modtage andet, men når en kontrakt kræver det, holder disse kald det nede på et simpelt konfigurationsvalg i stedet for et separat værktøj

Den anden betydning af "fladgørelse" (flatten)

Ordet "flatten" skaber ofte forvirring, fordi det også betegner en helt anden operation: nemlig at brænde AcroForm-feltudseender ind i sidens indholdsstrøm, indtil der ikke er nogen interaktive objekter tilbage. HotPDF har ikke en API til dette i øjeblikket, og det er vigtigt at vide nu snarere end halvvejs inde i et projekt. Hvad biblioteket giver dig i stedet, er låsning på feltniveau, når feltet oprettes, understøttet af dokumenttilladelser:

// 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

Vær ærlig om, hvad det giver dig, og hvad det ikke gør. Et skrivebeskyttet (read-only) felt er stadig et formularobjekt. Det vises i fremviserens feltpanel, dets værdi er læsbar via formular-API'en, og et værktøj, der skriver filen om, kan fjerne skrivebeskyttelsesflaget igen. Tilladelsesflag hæver barren, men afhænger af, at fremviseren vælger at respektere dem, en begrænsning, som ISO 32000-1 angiver klart. Når en myndighed insisterer på, at en arkiveret registrering slet ikke må indeholde formularobjekter, er det ærlige svar med HotPDF i dag at genopbygge dokumentet: Læs værdierne ud, og tegn dem derefter som almindeligt TextOut-indhold på en ny side, i stedet for at pakke skrivebeskyttelsesflag ind som fladgørelse. Én ting, du skal huske i forhold til tilladelser, er, at CryptKeyLength skal indstilles før BeginDoc; resten findes i vores artikel om AES-256-kryptering og -tilladelser

Hvad XFA betyder for arkiveringskrav

Både PDF/A og PDF/X afviser XFA fuldstændigt. En pipeline, der føder et ISO 19005-arkiv, skal derfor konvertere først, og rækkefølgen kan ikke diskuteres: indlæs, FlattenLoadedXFA, gem, og kør derefter arkiveringsgenerering eller validering på det resulterende AcroForm-dokument. Behandl ikke konverteringen som et bevis på overholdelse. Den retter formularmodellen, men efterlader skrifttyper, farver og metadata nøjagtigt som de var, så valider outputtet med veraPDF, før du stoler på det. Når formularen først er overført til AcroForm-siden, får dens adfærd sit eget sæt af kontroller. JavaScript-udløsere, indsendelseshandlinger og valideringsscripts dækkes i artiklen om HotPDF AcroForm-felter og -handlinger

XFA-registrerings-, konverterings- og formular-API'erne vist her leveres med HotPDF Component til Delphi og C++Builder, hvis dokumentation sporer XFA-funktionssættet, som det er vokset gennem de seneste udgivelser