Τεχνικό Άρθρο

Επιπεδοποίηση XFA σε AcroForm στο Delphi με τη χρήση του HotPDF

Δύο φόρμες μπορεί να κουβαλούν τα ίδια πεδία και να συμπεριφέρονται εντελώς διαφορετικά. Ένα AcroForm κρατά τα πεδία του ως συνηθισμένα αντικείμενα PDF που κάθονται πάνω σε πραγματικό περιεχόμενο σελίδας, οπότε κάθε συμμορφούμενος αναγνώστης το σχεδιάζει. Μια δυναμική φόρμα XFA δεν κρατά σχεδόν τίποτα ως PDF: τα πεδία, η διάταξη, ακόμη και η γεωμετρία σελίδας ζουν μέσα σε ένα πακέτο XML, και οι ορατές σελίδες παράγονται κατά το άνοιγμα από μια μηχανή διάταξης που μόνο η Adobe κυκλοφόρησε ευρέως. Δώστε αυτό το αρχείο σε ένα πρόγραμμα προβολής ιστού, έναν renderer αρχειοθέτησης, ή έναν εξαγωγέα κειμένου και δεν παίρνετε τη φόρμα. Παίρνετε μία μόνο γκρι σελίδα που γράφει "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." Όποιος έχει απορροφήσει κρατικά ή ασφαλιστικά έγγραφα αναγνωρίζει αυτή τη σελίδα με την πρώτη ματιά

Το placeholder δεν είναι αλλοίωση. Είναι ακριβώς αυτό που ορίζει η μορφή ότι πρέπει να συμβαίνει όταν δεν υπάρχει επεξεργαστής XFA, και από το 2026 αυτό περιγράφει σχεδόν κάθε πρόγραμμα προβολής εκτός του desktop Acrobat. Οπότε η πρακτική κίνηση είναι να μετατρέψετε τη δυναμική φόρμα σε απλό AcroForm προτού φτάσει σε οτιδήποτε παρακάτω στη ροή. Το HotPDF, η βιβλιοθήκη PDF της losLab για Delphi και C++Builder, κάνει αυτή τη μετατροπή σε κώδικα, ξαναχτίζοντας τη φόρμα XML ως εγγενή πεδία σε εγγενείς σελίδες

HotPDF: Παράλληλη σύγκριση μιας φόρμας AcroForm, της οποίας οι σελίδες, τα widgets και οι τιμές ζουν όλα στο PDF, και μιας δυναμικής φόρμας XFA που δείχνει σελίδα placeholder χωρίς μηχανή XFA
Το AcroForm κρατά σελίδες, widgets και τιμές μέσα στο PDF ώστε κάθε αναγνώστης ζωγραφίζει τη φόρμα, ενώ το δυναμικό XFA τα κρύβει πίσω από το Please-wait placeholder

Γιατί τα δύο μοντέλα δεν μπορούν να συνυπάρξουν

Το AcroForm ορίζεται στο ISO 32000-1 §12.7. Κάθε πεδίο είναι ένα αντικείμενο PDF με μια widget annotation και ένα appearance stream, η σελίδα είναι γνήσιο περιεχόμενο PDF, και τα δεδομένα κάθονται από πάνω του. Το XFA το αντιστρέφει αυτό: η φόρμα είναι ένα έγγραφο XML, ένα πακέτο XDP αποθηκευμένο στην καταχώριση /XFA του λεξικού AcroForm, και οι σελίδες PDF μιας δυναμικής φόρμας κρατούν μόνο το placeholder "Please wait" και τίποτα άλλο, επειδή το πραγματικό περιεχόμενο δεν σειριοποιήθηκε ποτέ ως PDF. Ένας αναγνώστης επεξεργάζεται ένα αρχείο ως το ένα μοντέλο ή το άλλο. Αγνοήστε την καταχώριση /XFA και βλέπετε το άδειο κέλυφος· σεβαστείτε την χωρίς μηχανή XFA και βλέπετε την προειδοποίηση. Το ISO 32000-2 τερμάτισε τη συζήτηση αφαιρώντας το XFA από το PDF 2.0, που είναι ο κύριος λόγος που το "μετατρέψτε όσο ακόμη μπορείτε" μετατράπηκε από ακραία περίπτωση σε συνήθη πολιτική εισαγωγής

Πριν μετατρέψετε οτιδήποτε, ταξινομήστε το, επειδή δεν εμφανίζει κάθε αρχείο XFA το placeholder. Οι στατικές φόρμες XFA κυκλοφορούν με προαποδοσμένες σελίδες PDF δίπλα στο XML, οπότε εμφανίζονται παντού και δυσλειτουργούν μόνο κατά τη συμπλήρωση. Οι δυναμικές φόρμες κυκλοφορούν μόνο με το placeholder και είναι άχρηστες μέχρι να μετατραπούν. Αυτό που πρέπει να εμπιστεύεστε είναι το ίδιο το έγγραφο, ποτέ την επέκταση ή τον αποστολέα. Ένα αρχείο που αποδίδει πραγματικό περιεχόμενο σε ένα πρόγραμμα προβολής που δεν είναι Adobe αλλά εξακολουθεί να φέρει καταχώριση /XFA είναι στατικό ή υβριδικό· ένα αρχείο που εμφανίζει τη σελίδα προειδοποίησης είναι δυναμικό. Καταγράψτε σε ποια κατηγορία προσγειώθηκε κάθε αρχείο εισαγωγής. Τα δύο είδη σπάνε με διαφορετικούς τρόπους αργότερα, και ένα ticket για μια κενή αρχειοθετημένη φόρμα κλείνει σε δευτερόλεπτα όταν το log εισαγωγής ήδη γράφει "dynamic XFA, converted, 47 fields mapped, 2 warnings"

Μετατροπή ενός φορτωμένου εγγράφου XFA σε εγγενή πεδία

Η μετατροπή τρέχει πάνω σε ένα έγγραφο ήδη στη μνήμη. Το FlattenLoadedXFA αναλύει το template XFA και τα πακέτα δεδομένων του, διατάσσει τη φόρμα, και την ξαναχτίζει ως πεδία AcroForm σε πραγματικές σελίδες PDF:

var
  Pdf: THotPDF;
  MappedCount, I: Integer;
  Warnings: TStrings;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.LoadFromFile('dynamic_xfa.pdf');
    MappedCount := Pdf.FlattenLoadedXFA(True);   // True = τα πεδία παραμένουν επεξεργάσιμα
    Warnings := Pdf.XFAFlattenWarnings;
    for I := 0 to Warnings.Count - 1 do
      Log('XFA flatten warning: ' + Warnings[I]); // μη αντιστοιχισμένα στοιχεία
    Pdf.SaveLoadedDocument('native_acroform.pdf');
    Log(Format('Mapped %d fields', [MappedCount]));
  finally
    Pdf.Free;
  end;
end;

Η τιμή επιστροφής και η λίστα προειδοποιήσεων είναι έξοδος, όχι θόρυβος debug, οπότε κρατήστε και τα δύο. Η μετατροπή χάνει πληροφορία εκ φύσεως: τα scripting XFA, τα υπολογιζόμενα πεδία, και η δυναμική συμπεριφορά subform δεν έχουν αντίστοιχο στο AcroForm, και το XFAFlattenWarnings ονομάζει κάθε στοιχείο template που δεν αντιστοιχίστηκε. Αρχειοθετήστε το μετατρεπόμενο αρχείο χωρίς τη λίστα προειδοποιήσεών του και κάποια μέρα θα κοιτάτε ένα κενό κουτί συνόλων σε ένα αρχειοθετημένο αντίγραφο χωρίς κανένα αρχείο του γιατί. Η σημαία Editable ελέγχει αν τα νέα πεδία παραμένουν συμπληρώσιμα. Περάστε True όταν οι άνθρωποι συνεχίζουν να δουλεύουν με τη φόρμα αργότερα, και κλειδώστε τις τιμές όταν ο στόχος είναι μια παγωμένη εγγραφή

Ο έλεγχος μιας μετατροπής είναι εν μέρει οπτικός, εν μέρει δομικός, και χρειάζεστε και τα δύο μισά. Το δομικό μισό είναι εύκολο: επιβεβαιώστε ότι ο αριθμός πεδίων ταιριάζει με το MappedCount. Το οπτικό μισό είναι αυτό που πιάνει πραγματική ζημιά. Ανοίξτε την πηγαία φόρμα στο desktop Acrobat, ακόμη το μόνο πρόγραμμα προβολής που τρέχει τη μηχανή XFA, δίπλα στο μετατρεπόμενο αρχείο σε έναν συνηθισμένο αναγνώστη, και συγκρίνετε τιμές και διάταξη σε τουλάχιστον ένα συμπληρωμένο δείγμα ανά template. Μια ημερομηνία που η μηχανή XFA εμφάνιζε ως 2026-06-11 μπορεί να προσγειωθεί στο αντίγραφο AcroForm ως ακατέργαστη, μη μορφοποιημένη τιμή, και μόνο τα μάτια σας θα το πιάσουν αυτό

Ροή ταξινόμησης εισαγωγής για έγγραφα XFA σε Delphi: αρχεία που αποδίδουν πραγματικό περιεχόμενο εκτός Acrobat είναι στατικά ή υβριδικά, ενώ αρχεία που δείχνουν τη σελίδα Please-wait είναι δυναμικά και πρέπει να μετατραπούν
Οι υβριδικές φόρμες αποδεικνύονται αποδίδοντας πραγματικό περιεχόμενο σε προβολείς εκτός Adobe, ενώ οι δυναμικές φόρμες αποκαλύπτονται μόνο μέσω της σελίδας placeholder

Όταν η είσοδος είναι ένα πακέτο XDP

Δεν ξεκινά κάθε εργασία από ένα συμπληρωμένο PDF. Μερικές φορές λαμβάνετε το πακέτο XDP μόνο του, εξαγόμενο από ένα εργαλείο σχεδίασης φορμών ή παραδομένο από ένα σύστημα συνεργάτη. Το ApplyXFAAsAcroForm παραλείπει το βήμα φόρτωσης και εφαρμόζει το πακέτο απευθείας στο τρέχον έγγραφο:

Αγωγός HotPDF που επιπεδώνει ένα φορτωμένο δυναμικό έγγραφο XFA σε επεξεργάσιμα πεδία AcroForm σε Delphi, αναδεικνύοντας μη χαρτογραφημένα scripting και υπολογιζόμενα πεδία μέσω XFAFlattenWarnings
Η FlattenLoadedXFA αναλύει και μεταφέρει τα πακέτα XDP σε επεξεργάσιμα πεδία AcroForm, και το XFAFlattenWarnings καταγράφει κάθε στοιχείο που δεν μπόρεσε να χαρτογραφηθεί
XDPBytes := TFile.ReadAllBytes('benefit-claim.xdp');
MappedCount := Pdf.ApplyXFAAsAcroForm(XDPBytes, True);

Η ίδια ομάδα κλήσεων τρέχει επίσης προς την άλλη κατεύθυνση, για τη σπανιότερη περίπτωση όπου πρέπει να εκπέμψετε XFA αντί να το καταναλώσετε. Το AddXFAPacket επισυνάπτει μεμονωμένα ονομασμένα πακέτα όπως 'xdp' ή 'config'. Το SetXFADocument εγκαθιστά ένα πλήρες payload ενιαίου stream σε μία κλήση. Το ClearXFAPackets σβήνει την καταχώριση ώστε να ξεκινήσετε από την αρχή, και το AddXFASignaturePacket ενσωματώνει υλικό XAdES για ροές εργασίας που υπογράφουν απευθείας τα δεδομένα φόρμας XML. Η παραγωγή XFA το 2026 είναι μια εξειδικευμένη ανάγκη, σχεδόν πάντα επιβεβλημένη από έναν παλιό καταναλωτή που αρνείται οτιδήποτε άλλο, αλλά όταν μια σύμβαση το κατονομάζει αυτές οι κλήσεις το κρατούν σε μια απλή επιλογή διαμόρφωσης αντί για ξεχωριστό εργαλείο

Η άλλη σημασία του "flatten"

Η λέξη "flatten" μπερδεύει πολλές συζητήσεις, επειδή ονομάζει μια εντελώς δεύτερη λειτουργία: να καίει τις εμφανίσεις πεδίων AcroForm μέσα στο content stream της σελίδας μέχρι να μην απομείνει κανένα διαδραστικό αντικείμενο. Το HotPDF δεν έχει API για αυτό σήμερα, και θέλετε να το ξέρετε τώρα και όχι στη μέση ενός έργου. Αυτό που σας δίνει αντ' αυτού η βιβλιοθήκη είναι κλείδωμα σε επίπεδο πεδίου κατά τη δημιουργία του πεδίου, υποστηριζόμενο από δικαιώματα εγγράφου:

// Κλείδωμα της τιμής κατά τη δημιουργία πεδίου: πεδίο κειμένου μόνο για ανάγνωση
Pdf.CurrentPage.AddTextField('CaseNumber', 'BC-2026-0117',
  Rect(50, 700, 220, 720), 0, [ffReadOnly]);

// Διπλή ασφάλεια: περιορισμός συμπλήρωσης φόρμας σε επίπεδο εγγράφου
Pdf.ActivateProtection := True;
Pdf.CryptKeyLength := aes256;
Pdf.OwnerPassword := 'records-owner';
Pdf.ProtectOptions := [prPrint, prInformationCopy, prExtractContent];
// δικαίωμα συμπλήρωσης παρακρατείται: το prFillAnnotations απουσιάζει από το σύνολο

Να είστε ξεκάθαροι για το τι σας εξασφαλίζει αυτό και τι όχι. Ένα πεδίο μόνο για ανάγνωση παραμένει αντικείμενο φόρμας. Εμφανίζεται στον πίνακα πεδίων του προγράμματος προβολής, η τιμή του διαβάζεται μέσω του API φόρμας, και ένα εργαλείο που ξαναγράφει το αρχείο μπορεί να καθαρίσει ξανά τη σημαία μόνο-για-ανάγνωση. Οι σημαίες δικαιωμάτων ανεβάζουν τον πήχη αλλά εξαρτώνται από το αν το πρόγραμμα προβολής επιλέγει να τις σεβαστεί, έναν περιορισμό που το ISO 32000-1 δηλώνει ξεκάθαρα. Όταν ένας ρυθμιστής επιμένει ότι μια αρχειοθετημένη εγγραφή δεν πρέπει να περιέχει καθόλου αντικείμενα φόρμας, η ειλικρινής απάντηση με το HotPDF σήμερα είναι να ξαναχτίσετε το έγγραφο: διαβάστε τις τιμές, έπειτα σχεδιάστε τις ως συνηθισμένο περιεχόμενο TextOut σε μια καινούργια σελίδα, αντί να ντύνετε σημαίες μόνο-για-ανάγνωση ως flattening. Ένα πράγμα που πρέπει να θυμάστε στη διαδρομή δικαιωμάτων είναι ότι το CryptKeyLength πρέπει να οριστεί πριν το BeginDoc· τα υπόλοιπα βρίσκονται στο άρθρο μας για την κρυπτογράφηση AES-256 και τα δικαιώματα

Τι σημαίνει το XFA για την αρχειακή συμμόρφωση

Τα PDF/A και PDF/X απορρίπτουν και τα δύο εντελώς το XFA. Ένας αγωγός που τροφοδοτεί ένα αρχείο ISO 19005 πρέπει επομένως να μετατρέπει πρώτα, και η σειρά δεν είναι διαπραγματεύσιμη: φόρτωση, FlattenLoadedXFA, αποθήκευση, έπειτα εκτέλεση δημιουργίας ή επικύρωσης αρχειοθέτησης στο αποτέλεσμα AcroForm. Μην αντιμετωπίζετε τη μετατροπή ως απόδειξη συμμόρφωσης. Διορθώνει το μοντέλο φόρμας και αφήνει γραμματοσειρές, χρώμα και μεταδεδομένα ακριβώς όπως ήταν, οπότε επικυρώστε την έξοδο με το veraPDF προτού την εμπιστευτείτε. Μόλις η φόρμα βρεθεί στην πλευρά AcroForm, η συμπεριφορά της αποκτά το δικό της σύνολο ελέγχων. Οι ενεργοποιητές JavaScript, οι ενέργειες submit, και τα σενάρια επικύρωσης καλύπτονται στο άρθρο για τα πεδία και τις ενέργειες AcroForm του HotPDF

Τα API καταχώρισης, μετατροπής και φόρμας XFA που παρουσιάζονται εδώ κυκλοφορούν με το HotPDF Delphi Component για Delphi και C++Builder, του οποίου η τεκμηρίωση παρακολουθεί το σύνολο χαρακτηριστικών XFA καθώς έχει μεγαλώσει στις πρόσφατες εκδόσεις