Το PDF/A και το PDF/UA απαντούν σε δύο ερωτήματα που δεν έχουν καμία σχέση μεταξύ τους, και το να τα αντιμετωπίζετε ως ένα ενιαίο πλαίσιο ελέγχου «προσβασιμότητα και αρχειοθέτηση» είναι ο τρόπος με τον οποίο χαλασμένα αρχεία φτάνουν σε ένα αρχείο φορώντας ετικέτα συμμόρφωσης. Το PDF/A ρωτά αν ένα αρχείο θα εξακολουθεί να αποδίδεται πιστά σε είκοσι χρόνια. Το PDF/UA ρωτά αν η υποστηρικτική τεχνολογία μπορεί να το διαβάσει σήμερα. Ένα έγγραφο μπορεί να περάσει άνετα το ένα και να κοπεί στο άλλο, οπότε η μόνη έντιμη ετυμηγορία προκύπτει από την εκτέλεση και των δύο, και μάλιστα προτού γραφτεί το αρχείο, όχι αφού κάποιο επόμενο σύστημα εμπιστευτεί το αναγνωριστικό συμμόρφωσης που είναι ψημένο μέσα στα μεταδεδομένα του. Αυτό το αναγνωριστικό είναι αυτοδήλωση. Τίποτα στη μορφή δεν απαιτεί να είναι αληθές, και μια εφαρμογή που γράφει «PDF/A-1b» μέσα στο XMP χωρίς να επικυρώνει έναντι του προτύπου παράγει αρχείο που φαίνεται συμμορφούμενο σε κάθε καταναλωτή ο οποίος διαβάζει μόνο την ετικέτα. Η losLab PDF Library (PDF Library for Delphi) κλείνει αυτό το κενό για Delphi και C++Builder ενσωματώνοντας και τους δύο επικυρωτές μέσα στη βιβλιοθήκη, ώστε ο έλεγχος να τρέχει εντός διεργασίας χωρίς εξωτερική υπηρεσία που πρέπει να στηθεί
Δύο πρότυπα που κόβουν αρχεία για αντίθετους λόγους
Το ISO 19005 (PDF/A) είναι συμβόλαιο αναπαραγωγής. Ένα συμμορφούμενο αρχείο πρέπει να αποδίδεται πανομοιότυπα δεκαετίες από τώρα σε λογισμικό που δεν είδε ποτέ το σύστημα που το παρήγαγε, οπότε οι κανόνες επιτίθενται στις εξωτερικές εξαρτήσεις: κάθε γραμματοσειρά ενσωματωμένη, το χρώμα αγκυρωμένο σε ενσωματωμένο ICC OutputIntent ή εκφρασμένο σε ανεξάρτητο από συσκευή χώρο, καμία κρυπτογράφηση στο PDF/A-1, καθόλου JavaScript, μεταδεδομένα XMP που συμφωνούν με το λεξικό πληροφοριών του εγγράφου. Το ISO 14289 (PDF/UA) είναι αντιθέτως συμβόλαιο σημασιολογίας. Η υποστηρικτική τεχνολογία πρέπει να διατρέξει το έγγραφο και να βγει με νόημα, το οποίο ζει σε εντελώς διαφορετικό επίπεδο: πλήρες δέντρο δομής, εναλλακτικό κείμενο στις εικόνες, τίτλος εγγράφου ορισμένος για εμφάνιση, επίπεδα επικεφαλίδων που δεν παραλείπουν βαθμίδες, σχέσεις κεφαλίδων πίνακα που επιβιώνουν όταν η σελίδα φύγει από την οθόνη
Επειδή τα δύο πρότυπα αστυνομεύουν διαφορετικά επίπεδα, τα αρχεία που σας δαγκώνουν είναι εκείνα που κάθονται ανάμεσά τους. Ένα τέλειο για αρχειοθέτηση έγγραφο μπορεί να είναι βουβό για έναν αναγνώστη οθόνης. Ένα υπέροχα tagged έγγραφο μπορεί να παραπέμπει σε γραμματοσειρά επιφάνειας εργασίας που δεν θα υπάρχει σε δέκα χρόνια. Οι εκδόσεις του δημόσιου τομέα είναι το συνηθισμένο σημείο όπου προσγειώνονται και οι δύο απαιτήσεις ταυτόχρονα, και μια ροή εργασίας εκεί δεν μπορεί να τις συμπτύξει σε μία πύλη. Τα ευρήματα πηγαίνουν σε διαφορετικούς ανθρώπους. Οι μη ενσωματωμένες γραμματοσειρές είναι ελάττωμα του κώδικα που παράγει το PDF, ενώ το ελλιπές εναλλακτικό κείμενο ανήκει σε όποιον έχει τα πρότυπα περιεχομένου, και μια αναφορά που ανακατεύει τα δύο απλώς προωθείται δύο φορές
Το ποιο μέρος του PDF/A στοχεύετε μετράει όσο και το αν το πετυχαίνετε. Το PDF/A-1 είναι παγωμένο στο PDF 1.4 και απορρίπτει τη διαφάνεια και το JPEG2000, στα οποία η σύγχρονη έξοδος αναφορών καταφεύγει χωρίς δεύτερη σκέψη. Το PDF/A-2 (ISO 19005-2, χτισμένο πάνω στο ISO 32000-1) δέχεται και τα δύο και είναι η λογική προεπιλογή για ένα νέο αρχείο. Το PDF/A-3 πηγαίνει παραπέρα και επιτρέπει ενσωματωμένα αρχεία οποιουδήποτε τύπου, πράγμα στο οποίο στηρίζονται οι ρυθμιζόμενες μορφές ηλεκτρονικής τιμολόγησης. Μια ομάδα που το 2026 τυποποιεί ακόμη στο PDF/A-1b συνήθως κουβαλά μια απαίτηση που κάποιος έγραψε πριν από δεκαπέντε χρόνια, και η επαναδιαπραγμάτευση του στοχευόμενου μέρους είναι συχνά φθηνότερη από την αφαίρεση της διαφάνειας από κάθε γράφημα που εκπέμπει το σύστημα
Δομημένα ευρήματα τη στιγμή της παραλαβής
Το σημείο εισόδου του επίπεδου API είναι η CheckFileCompliance, με επιλογέα ελέγχου 1 για PDF/A και 2 για PDF/UA. Επιστρέφει ένα handle λίστας συμβολοσειρών του οποίου τα στοιχεία είναι μεμονωμένα ευρήματα, ένα ανά γραμμή, που είναι ακριβώς η μορφή την οποία θέλει να διατρέξει μια αυτοματοποιημένη πύλη:
function GateArchiveUpload(Pdf: TPDFlib; const FileName: string): Boolean;
var
ListId, I: Integer;
begin
ListId := Pdf.CheckFileCompliance(FileName, '', 1, 0); // 1 = PDF/A
if ListId = 0 then
begin
// 0 σημαίνει «κανένα εύρημα» Ή «μη αναγνώσιμο αρχείο» -- ξεχωρίστε τα πριν το περάσετε
Result := Pdf.LastErrorCode = 0;
Exit;
end;
for I := 0 to Pdf.GetStringListCount(ListId) - 1 do
LogFinding(FileName, Pdf.GetStringListItem(ListId, I));
Pdf.ReleaseStringList(ListId);
Result := False;
end;
Δύο λεπτομέρειες κρίνουν αν αυτό τρέχει χωρίς επιτήρηση. Η πρώτη είναι μια επιστρεφόμενη τιμή που σημαίνει δύο αντίθετα πράγματα. Η CheckFileCompliance επιστρέφει 0 όταν το αρχείο είναι πλήρως συμμορφούμενο και επίσης όταν το αρχείο δεν μπόρεσε να ανοίξει καθόλου, επειδή εσωτερικά μια κενή λίστα αποτελεσμάτων καταρρέει στο 0 και στις δύο περιπτώσεις. Μια πύλη που διαβάζει το 0 ως επιτυχία θα περάσει κατεστραμμένα uploads κατευθείαν μέσα στο αρχείο, οπότε ξεχωρίστε τις περιπτώσεις με το LastErrorCode προτού εμπιστευτείτε το μηδέν, όπως κάνει η πύλη παραπάνω. Η δεύτερη αφορά το πού βρίσκεται το αρχείο στον κύκλο ζωής του. Ο ελεγκτής τρέχει πάνω στον streaming reader της βιβλιοθήκης αντί για το πλήρες μοντέλο εγγράφου, ανοίγοντας το αρχείο απευθείας με κοινή χρήση ανάγνωσης και χωρίς να καλεί ποτέ την LoadFromFile, γι' αυτό και μπορεί να μασήσει είσοδο πολλών gigabyte χωρίς να χτίσει δέντρο αντικειμένων. Το ίδιο streaming άνοιγμα αποτυγχάνει όσο μια άλλη διεργασία κρατά ακόμη το αρχείο για εγγραφή, και ένα upload σε εξέλιξη είναι ακριβώς αυτή η κατάσταση. Βάλτε την πύλη αφού ολοκληρωθεί η μεταφορά
Ο σχεδιασμός με streaming αποδίδει ξανά υπό φόρτο. Κάθε έλεγχος ανοίγει την είσοδό του μόνο για ανάγνωση και τη μοιράζεται για ανάγνωση, οπότε ένας έλεγχος ολόκληρου σώματος εγγράφων κλιμακώνεται σε νήματα ή διεργασίες εργασίας με ένα instance TPDFlib ανά εργάτη και χωρίς ανταγωνισμό μεταξύ τους. Ο πόρος που χρειάζεται πειθαρχία είναι το ίδιο το handle. Κάθε μη μηδενικό αποτέλεσμα της CheckFileCompliance παραμένει δεσμευμένο μέχρι να καλέσετε την ReleaseStringList, και μια μακρόβια πύλη που ξεχνά να τα απελευθερώνει δεν καταρρέει, απλώς αιμορραγεί μνήμη αργά μέχρι να πάει κάποιος να ψάξει το γιατί
Αναφορές για ανθρώπους, diffs για πύλες build
Μια λίστα ευρημάτων είναι η σωστή μορφή για μια πύλη και η λάθος μορφή για ένα email προς την ομάδα των προτύπων. Η CreatePreflightReport αποδίδει την ίδια ανάλυση ως αναγνώσιμο κείμενο, η CreatePreflightReportEx προσθέτει επιλογέα μορφής αναφοράς, και η SavePreflightReport τη γράφει στον δίσκο ώστε η αναφορά να μπορεί να ταξιδέψει μέσα στο παραδοτέο πακέτο εγγράφων. Αρκετά συμβόλαια αρχειοθέτησης κάνουν αυτή την αναφορά παραδοτέο από μόνη της, όχι απλώς εσωτερικό τεχνούργημα
Το μέλος αυτής της οικογένειας που κερδίζει αθόρυβα τη θέση του είναι η ComparePreflightReports. Η συμμόρφωση είναι επιφάνεια παλινδρόμησης όπως κάθε άλλο κομμάτι συμπεριφοράς. Μια τροποποίηση προτύπου, μια νεοαποκτηθείσα εταιρική γραμματοσειρά ή μια αναβάθμιση βιβλιοθήκης μπορεί η καθεμία να εισαγάγει ένα εύρημα που δεν υπήρχε στην προηγούμενη κυκλοφορία, και καμία τους δεν το ανακοινώνει. Κρατήστε golden αναφορές για ένα σύνολο αντιπροσωπευτικών εγγράφων υπό έλεγχο εκδόσεων, αναδημιουργήστε τες μετά από κάθε αλλαγή, και τρέξτε την ComparePreflightReports για να υπολογίσετε τη διαφορά. Ένα κενό diff είναι τεχνούργημα κυκλοφορίας που αξίζει να κρατηθεί. Ένα απροσδόκητο εύρημα ρίχνει το build, που είναι πολύ φθηνότερο σημείο για να το ανακαλύψετε από ό,τι ο έλεγχος συμμόρφωσης
Παραγωγή εξόδου που περνά από την πρώτη εκτέλεση
Το preflight αξίζει τα λεφτά του σε αρχεία που φτάνουν από αλλού. Για έγγραφα που παράγει ο δικός σας κώδικας, το να βρίσκετε παραβάσεις μετά την παραγωγή και να τις μπαλώνετε εκ των υστέρων είναι ο αργός δρόμος. Το PDF Library for Delphi διαθέτει μια λειτουργία παραγωγής για κάθε πρότυπο, και μπορείτε να ενεργοποιήσετε και τις δύο για το ίδιο έγγραφο:
var
Pdf: TPDFlib;
Diag: WideString;
begin
Pdf := TPDFlib.Create;
try
Pdf.NewDocument;
Pdf.SetPDFAMode(1);
Pdf.LoadOutputIntentProfile('sRGB-IEC61966-2.1.icc', 'RGB');
Pdf.SetPDFUAMode('en-US');
Pdf.SetInformation(1, 'Quarterly Statement'); // /Title: απαιτείται για το PDF/UA
// ... σχεδιάστε εδώ tagged περιεχόμενο ...
Diag := Pdf.GetPDFUADiagnostics;
if Diag <> '' then
Writeln('fix before shipping: ', Diag);
Pdf.SaveToFile('statement.pdf');
// το preflight που μετράει τρέχει πάνω στο αποθηκευμένο αρχείο:
Writeln(Pdf.CreatePreflightReport('statement.pdf', '', 1, 0));
finally
Pdf.Free;
end;
end;
Η παγίδα κρύβεται τη στιγμή της αποθήκευσης. Αρκετές από τις επιδιορθώσεις συμμόρφωσης γίνονται ενώ το έγγραφο σειριοποιείται και όχι όταν ενεργοποιείτε τη λειτουργία: η επιβολή της σημαίας εκτύπωσης στους σχολιασμούς, η εγγραφή του προεπιλεγμένου AFRelationship για τα ενσωματωμένα αρχεία PDF/A-3, η κανονικοποίηση της σειράς στηλοθετών και των περιγραφών των πεδίων φόρμας για το PDF/UA. Το έγγραφο που κάθεται στη μνήμη δεν είναι byte προς byte ίδιο με εκείνο που προσγειώνεται στον δίσκο, οπότε η μόνη ετυμηγορία preflight που σημαίνει κάτι είναι εκείνη που υπολογίζεται από το αποθηκευμένο αρχείο. Επικυρώστε το ίδιο το statement.pdf. Μη συμπεραίνετε τη συμμόρφωση από το αντικείμενο που βρίσκεται ακόμη στη μνήμη, επειδή τα bytes που θα κρίνατε δεν είναι τα bytes που παραδώσατε
Τα σενάρια τιμολόγησης που κουβαλούν μηχαναγνώσιμο XML δίπλα στο οπτικό έγγραφο ακολουθούν το μοτίβο ZUGFeRD και Factur-X, το οποίο είναι χτισμένο πάνω στο PDF/A-3. Αυτά θα πρέπει να ορίζουν ρητά τη σχέση του συνημμένου με την SetPDFA3DefaultAFRelationship, αφού το ISO 19005-3 απαιτεί κάθε ενσωματωμένο αρχείο να δηλώνει τον ρόλο του σε σχέση με το έγγραφο. Αφήστε την αόριστη και το ενσωματωμένο XML είναι απλώς ένα blob χωρίς δηλωμένο σκοπό, κάτι που ο επικυρωτής το αντιλαμβάνεται
Ανεξάρτητοι διαιτητές: veraPDF και Acrobat
Ένας παραγωγός δεν πρέπει να είναι ο μόνος κριτής της δικής του εξόδου. Οι ελεγκτές του PDF Library for Delphi σας δίνουν γρήγορες, δομημένες ετυμηγορίες εντός διεργασίας, που είναι αυτό που θέλετε στην κρίσιμη διαδρομή, αλλά η πύλη κυκλοφορίας για μια παρτίδα αρχειοθέτησης θα πρέπει να περνά την έξοδο και από έναν επικυρωτή που δεν έγραψε κανείς από την ομάδα σας. Το veraPDF είναι η υλοποίηση αναφοράς που συντηρείται από την κοινότητα για το PDF/A και το εργαλείο που τα περισσότερα αρχεία κατονομάζουν στα κριτήρια αποδοχής τους, οπότε είναι εκείνο με το οποίο πρέπει να ευθυγραμμιστείτε. Τα προφίλ preflight του Acrobat είναι χρήσιμος διαιτητής όταν το veraPDF και ο έλεγχος εντός διεργασίας διαφωνούν. Καταγράψτε το όνομα του επικυρωτή και την έκδοσή του δίπλα σε κάθε αποθηκευμένη αναφορά. Ο ισχυρισμός ότι ένα αρχείο πέρασε το veraPDF λέει ελάχιστα χωρίς τον αριθμό build που το πέρασε, αφού το εργαλείο σφίγγει τους κανόνες του από κυκλοφορία σε κυκλοφορία
Οι επικυρωτές όντως διαφωνούν στις παρυφές των προτύπων, και όταν συμβαίνει αυτό η απάντηση δεν είναι να διαλέξετε το εργαλείο που σας αρέσει. Συρρικνώστε το αρχείο σε ένα ελάχιστο δείγμα που εξακολουθεί να πυροδοτεί τη διαφωνία και διαβάστε το έναντι του κειμένου του προτύπου. Μία ώρα τέτοιας δουλειάς συνήθως αναδεικνύει ένα από δύο πράγματα: ένα γνήσιο σφάλμα εργαλείου που αξίζει να αναφερθεί ανάντη, ή μια ρήτρα που η ομάδα σας διαβάζει λάθος και θα έπρεπε να καταγράψει στις σημειώσεις συμμόρφωσης ώστε ο επόμενος να μην την ξαναδικάσει
Η κρυπτογραφημένη είσοδος έχει συντομότερο δρόμο. Και οι δύο ελεγκτές δέχονται όρισμα συνθηματικού, αλλά ένα αρχείο PDF/A-1 με λεξικό κρυπτογράφησης είναι ήδη μη συμμορφούμενο, επειδή το ISO 19005-1 απαγορεύει ρητά την κρυπτογράφηση, οπότε μια κρυπτογραφημένη υποβολή μπορεί να απορριφθεί προτού τρέξει οποιαδήποτε βαθύτερη ανάλυση. Το τι παραχωρεί στην πραγματικότητα ένα λεξικό κρυπτογράφησης είναι δουλειά από μόνο του, που καλύπτεται στον έλεγχο κρυπτογράφησης και δικαιωμάτων PDF
Τα ευρήματα PDF/UA σχεδόν πάντα ανάγονται στο πώς συντάχθηκε εξαρχής το δέντρο δομής, και οι τεχνικές tagging πίσω από αυτό βρίσκονται στο χτίσιμο δέντρων δομής tagged PDF στη Delphi. Τα αρχεία που απαιτούν επίσης ψηφιακές υπογραφές θα πρέπει να συνδυάζουν αυτή την πύλη με τη ροή εργασίας στο υπογραφή και επικύρωση PAdES. Η πλήρης αναφορά του API preflight βρίσκεται στη σελίδα προϊόντος losLab PDF Library for Delphi