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

Μετατροπή PDF σε PDF/A και επισκευή μεταδεδομένων του

Η ConvertToPDFA μετατρέπει ένα κοινό έγγραφο σε αρχειακό με μία κλήση: αφαιρεί ό,τι απαγορεύει το επιλεγμένο μέρος, προσθέτει ό,τι απαιτεί, δηλώνει το μέρος που διεκδικεί το έγγραφο, και κατόπιν ελέγχει το αποτέλεσμα. Η διεκδίκηση αναφέρεται ως ικανοποιημένη μόνο όταν ο έλεγχος περνά, και η GetPDFAConversionReport παραθέτει τι έγινε και τι εξακολουθεί να στέκεται εμπόδιο

Αυτή η τελευταία ιδιότητα είναι η σχεδιαστική απόφαση που αξίζει να αναλυθεί. Ένας μετατροπέας που σφραγίζει τη διεκδίκηση χωρίς να ελέγχει είναι χειρότερος από καθόλου μετατροπέα, επειδή ένα αρχείο που λέει ότι είναι αρχειακό και δεν είναι περνά κατευθείαν μέσα από τα ίδια τα συστήματα που αλλιώς θα το είχαν πιάσει. Η αποτυχία αναδύεται χρόνια αργότερα, σε έναν έλεγχο, πάνω σε ένα έγγραφο που δεν μπορεί να αναγεννήσει κανείς

Γιατί ένα PDF που φαίνεται έγκυρο αποτυγχάνει σε έλεγχο PDF/A;

Πιο συχνά επειδή διαφωνούν τα δύο μέρη όπου ένα PDF λέει ποιος το έγραψε. Ένας validator διαβάζει και το λεξικό πληροφοριών εγγράφου και το πακέτο XMP και απορρίπτει ένα αρχείο όπου διαφέρουν — και τα περισσότερα αρχεία που αποτυγχάνουν σε αυτό το σημείο απλώς δεν είχαν καθόλου γραμμένο το μισό XMP

Η RepairDocumentMetadata τα φέρνει σε συμφωνία και επιστρέφει πόσες καταχωρίσεις επισκεύασε. Όταν μόνο το ένα μισό φέρει τιμή, το άλλο συμπληρώνεται από αυτό, οπότε τίποτα όσο ήδη καταγεγραμμένο δεν πετιέται. Κανείς δεν χρειάζεται να αποφασίσει ποιο αντίγραφο είναι αυθεντικό, επειδή στην πράξη το ένα αντίγραφο είναι κενό

Υπάρχει μια δεύτερη επισκευή στην ίδια κλήση που πιάνει μια πιο λεπτή περίπτωση. Ένα έγγραφο ρυθμισμένο σε λειτουργία PDF/A παίρνει πίσω την αναγνώριση προτύπων αν είχε χαθεί, κάτι που συμβαίνει όποτε ένας καλών παρέχει δικό του πακέτο XMP. Χωρίς αυτή την αναγνώριση ένας validator διαβάζει το αρχείο ως κοινό PDF και αναφέρει κάθε κανόνα του διεκδικημένου μέρους ως ανικανοποίητο — μια εντυπωσιακή αποτυχία με μια μικρή αιτία

var
  Lib: TPDFlib;
  Repaired: Integer;
begin
  Lib := TPDFlib.Create;
  try
    Lib.LoadFromFile('incoming.pdf', '');
    Repaired := Lib.RepairDocumentMetadata;
    Log(Format('%d metadata entries brought into agreement', [Repaired]));
    Lib.SaveToFile('incoming-fixed.pdf');
  finally
    Lib.Free;
  end;
end;

Επιλογή του μέρους πριν τη μετατροπή

Η SetPDFAMode και η ConvertToPDFA μοιράζονται την ίδια αρίθμηση λειτουργιών, και τρεις από τις τιμές είναι πρόσφατες. Η λειτουργία 9 είναι PDF/A-4, το μέρος χτισμένο πάνω στο PDF 2.0. Η λειτουργία 10 είναι PDF/A-4e, που επιπλέον επιτρέπει 3D και rich media, και η λειτουργία 11 είναι PDF/A-4f, που επιτρέπει ένα ενσωματωμένο αρχείο οποιασδήποτε μορφής

Το μέρος 4 ταυτίζει τον εαυτό του διαφορετικά από τα μέρη πριν από αυτό: με αριθμό μέρους και έτος δημοσίευσης του μέρους του, χωρίς γράμμα συμμόρφωσης για το απλό PDF/A-4 και με το γράμμα E ή F για τις δύο επεκτάσεις. Ο έλεγχος αναγνωρίζει το μέρος 4, κρίνει τα αρχεία του έναντι του PDF 2.0 αντί του 1.7, και αναφέρει ένα αρχείο μέρους 4 που δεν αναγράφει το έτος αναθεώρησής του

Κάθε ενσωματωμένο αρχείο σε ένα έγγραφο μέρους 4 δηλώνει πώς σχετίζεται με το έγγραφο, όπως απαιτούν και τα μέρη 3 και 4. Αυτός είναι ο κανόνας που έπιανε παλιά τα κοινά συνημμένα: η σχέση γραφόταν μόνο για συνημμένα μετά το πρώτο και ποτέ για το τελευταίο, οπότε ένα έγγραφο με ένα μόνο συνημμένο — η κοινή περίπτωση — δεν έφερε καθόλου και απέτυχε σε επικύρωση ακριβώς σε αυτό το σημείο

var
  Verdict: Integer;
begin
  Lib.LoadFromFile('report.pdf', '');
  Verdict := Lib.ConvertToPDFA(9);        // 9 = PDF/A-4, 10 = 4e, 11 = 4f
  Memo1.Lines.Text := Lib.GetPDFAConversionReport;
  if Verdict = 1 then
    Lib.SaveToFile('report-pdfa4.pdf')
  else
    Log('conversion incomplete - see the report for what stands in the way');
end;

Σε τι χρησιμεύει η αναφορά μετατροπής

Στο να αποφασίσετε τι να κάνετε μετά. Μια μετατροπή που πετυχαίνει δεν χρειάζεται αναφορά· μια μετατροπή που δεν πετυχαίνει είναι όλος ο λόγος που υπάρχει η αναφορά. Κάποια εμπόδια μπορούν να αφαιρεθούν από έναν μετατροπέα και κάποια όχι — κρυπτογράφηση, απαγορευμένο περιεχόμενο που φέρει νόημα, ένα πρόγραμμα γραμματοσειράς που απλώς δεν υπάρχει πουθενά στο μηχάνημα. Η αναφορά διαχωρίζει τι έγινε από τι απομένει, που μετατρέπει το «η μετατροπή απέτυχε» σε ένα στοιχείο εργασίας

Αντιμετωπίστε την ετυμηγορία ως πύλη σε μια γραμμή παραγωγής παρτίδας. Μετατρέψτε, διαβάστε την ετυμηγορία, και δρομολογήστε το αρχείο: αρχειοθετήστε αυτά που πέρασαν, βάλτε τα υπόλοιπα σε ουρά για άνθρωπο με την αναφορά προσαρτημένη. Αυτό που δεν πρέπει να κάνετε είναι να αποθηκεύσετε την έξοδο μιας αποτυχημένης μετατροπής στο αρχείο επειδή φαίνεται καλύτερη από την είσοδο — φέρει τώρα μια διεκδίκηση που ο έλεγχος αρνήθηκε να επιβεβαιώσει

Ανάγνωση του σημείου που ήδη φέρει ένα αρχείο

Πριν μετατρέψετε οτιδήποτε, να ξέρετε τι λέει το έγγραφο για τον εαυτό του. Ένας έλεγχος PDF/A που δεν μπορεί να διαβάσει την υπάρχουσα σήμανση προτύπων κρίνει κάθε αρχείο έναντι του μέρους 1 ό,τι κι αν δηλώνει, που σημαίνει ένα απολύτως έγκυρο PDF/A-2 ή PDF/A-3 έγγραφο αναφέρεται ως μη φέρον σήμανση και ως έχον υπερβολικά υψηλή έκδοση — το αντίθετο από την αλήθεια

Η σήμανση διαβάζεται είτε ο παραγωγός την έγραψε ως στοιχείο XMP είτε ως χαρακτηριστικό. Και οι δύο μορφές είναι κοινό XMP, και η αποδοχή μόνο μιας από αυτές αφήνει αρχεία από άλλους παραγωγούς να φαίνονται μη σημειωμένα. Αν έχετε αναρωτηθεί ποτέ γιατί ένα έγγραφο που επικυρώνεται αλλού αποτυγχάνει στη δική σας γραμμή παραγωγής, αυτό είναι ένα καλό μέρος να κοιτάξετε πρώτα

Απολύμανση πριν την αρχειοθέτηση, και το bug που αξίζει να ξέρετε

Η αρχειακή μετατροπή και η απολύμανση συχνά τρέχουν μαζί, επειδή το περιεχόμενο που θέλει να αφαιρέσει μια πολιτική ασφαλείας επικαλύπτεται σε μεγάλο βαθμό με το περιεχόμενο που απαγορεύει το PDF/A. Η SanitizeDocument αφαιρεί JavaScript, και η αφαίρεση του τελευταίου script αφαιρεί επίσης το κενό δέντρο ονομάτων που αφήνει πίσω — ένα δέντρο που αλλιώς θα εξακολουθούσε να λέει σε έναν αναγνώστη ότι το έγγραφο έφερε scripts

Αυτό το δεύτερο μισό μαθήθηκε με τον δύσκολο τρόπο: ένα off-by-one στη λίστα πακέτων σήμαινε ότι η απολύμανση ανέφερε αφαίρεση scripts ενώ δεν αφαιρούσε κανένα, οπότε ένα έγγραφο που είχε απολυμανθεί εξακολουθούσε να τρέχει τα scripts του όταν ανοιγόταν. Είναι ένα καλό επιχείρημα υπέρ της γενικής αρχής στην οποία στηρίζεται όλο αυτό το άρθρο — επαληθεύστε το αποτέλεσμα αντί να εμπιστεύεστε τη λειτουργία, στη δική σας γραμμή παραγωγής όσο και στη βιβλιοθήκη

Για το ευρύτερο αρχειακό έργο, δείτε τις αναλύσεις για το preflight PDF/A και PDF/UA, την πραγματική απόκρυψη και αφαίρεση περιεχομένου, και τα σχήματα επέκτασης XMP PDF/A-3 για Factur-X, που καλύπτει την πλευρά των μεταδεδομένων όταν το αρχειοθετημένο έγγραφο φέρει επίσης δομημένα δεδομένα τιμολογίου

Το PDFlibPas είναι μια native Pascal βιβλιοθήκη PDF για Delphi, C++Builder και Lazarus, οπότε μετατροπή, επισκευή και επικύρωση συμβαίνουν όλες μέσα στη δική σας διεργασία χωρίς εξωτερικό εργαλείο στην αλυσίδα — δείτε τη σελίδα προϊόντος PDFlibPas για τα υποστηριζόμενα μέρη PDF/A και πλατφόρμες