Το PDFlibPas μπορεί να επισημάνει ένα έγγραφο όσο αυτό σχεδιάζεται. Ενεργοποιήστε το SetAutoTagMode και οι κοινές κλήσεις DrawText γίνονται παράγραφοι, το κείμενο που σχεδιάζεται αμέσως μετά την RegisterHeading γίνεται τίτλος αντίστοιχου επιπέδου, οι κεφαλίδες και τα υποσέλιδα επανάληψης γίνονται artifacts που ο αναγνώστης παραλείπει, οι εικόνες γίνονται figures, και η DrawTableRows μεταφέρει τον πίνακα, τις γραμμές και τα κελιά του στο δέντρο δομής
Η εναλλακτική — και μέχρι πρόσφατα η μοναδική επιλογή — ήταν να τυλίγεται κάθε κλήση σχεδίασης σε BeginTag και EndTag με το χέρι. Αυτό λειτουργεί, και για έγγραφα με ασυνήθιστη δομή παραμένει το σωστό εργαλείο. Για μια κοινή αναφορά, τιμολόγιο ή κατάσταση, σημαίνει ότι η προσβασιμότητα της εξόδου εξαρτάται από το να μην ξεχάσει ποτέ κανείς ένα ζευγάρι, σε κάθε διαδρομή κώδικα που σχεδιάζει οτιδήποτε
Τι καλύπτουν τα bit της λειτουργίας
Η SetAutoTagMode δέχεται μια μάσκα bit και επιστρέφει την προηγουμένως ισχύουσα λειτουργία. Το AUTOTAG_TEXT (1) επισημαίνει το κείμενο ως παράγραφο, ή ως τίτλο όταν κάποιος είναι σε αναμονή. Το AUTOTAG_FURNITURE (2) μαρκάρει τις κεφαλίδες, τα υποσέλιδα και τους αριθμούς σελίδων επανάληψης ως artifacts. Το AUTOTAG_FIGURE (4) μετατρέπει μια σχεδιασμένη εικόνα σε figure, ή σε artifact όταν έχει δηλωθεί ως διακοσμητική. Το AUTOTAG_TABLE (8) μεταφέρει τους σχεδιασμένους πίνακες στο δέντρο δομής. Το AUTOTAG_DEFAULT είναι 15, δηλαδή και τα τέσσερα
Η ενεργοποίηση της λειτουργίας μαρκάρει επίσης το έγγραφο ως tagged, και αυτό το βήμα είναι λιγότερο καλλυντικό από όσο ακούγεται. Ένας αναγνώστης θεωρεί ένα έγγραφο μη tagged εκτός αν ο κατάλογος λέει διαφορετικά (ISO 32000-1 §14.7.1), οπότε ένα αρχείο που φέρει πλήρες δέντρο δομής χωρίς δήλωση /MarkInfo ανακοινώνεται από τις βοηθητικές τεχνολογίες ως μην έχοντας καμία δομή. Το δέντρο υπάρχει· τίποτα δεν το διαβάζει
var
Lib: TPDFlib;
begin
Lib := TPDFlib.Create;
try
Lib.SetOrigin(1);
Lib.SetAutoTagMode(AUTOTAG_DEFAULT); // text + furniture + figures + tables
Lib.AddStandardFont(4);
Lib.SetTextSize(18);
Lib.RegisterHeading(1, 'Annual service report');
Lib.DrawText(72, 96, 'Annual service report'); // becomes H1
Lib.SetTextSize(11);
Lib.DrawText(72, 130, 'Every unit installed before 2024 was inspected.');
Lib.SaveToFile('report.pdf');
finally
Lib.Free;
end;
end;
Πώς ξέρει ένας τίτλος σε ποιο κείμενο ανήκει;
Η RegisterHeading ονομάζει το επίπεδο για το επόμενο κείμενο που θα σχεδιαστεί, και περιμένει κείμενο. Αν σχεδιαστεί μια εικόνα ενδιάμεσα, η εικόνα γίνεται figure και ο τίτλος παραμένει σε αναμονή για το κείμενο που ακολουθεί. Αυτή η συμπεριφορά είναι σκόπιμη: η εναλλακτική, όπου η εικόνα παίρνει το επίπεδο τίτλου, παρήγαγε έγγραφα όπου ένα διακοσμητικό υπόμνημα κάτω από έναν τίτλο ανακοινωνόταν ως ο τίτλος
Ο ίδιος κανόνας «καταναλώνεται σε ένα στοιχείο» διέπει τα figures. Η RegisterFigure παρέχει την περιγραφή που θα φέρει η επόμενη εικόνα, και η RegisterDecoration δηλώνει την επόμενη εικόνα ως υπομνηματική γραμμή, περίγραμμα ή φόντο που δεν φέρει νόημα. Και οι δύο καταναλώνονται από μία εικόνα, ώστε μια μεταγενέστερη εικόνα να μην κληρονομεί ποτέ περιγραφή προορισμένη για προηγούμενη — αυτός είναι ο τρόπος με τον οποίο το εναλλακτικό κείμενο καταλήγει προσαρτημένο σε λάθος εικόνα σε χειροκίνητα tagged κώδικα
Η περιγραφή έχει μεγαλύτερη σημασία από οποιαδήποτε άλλη μεμονωμένη συμβολοσειρά σε ένα προσβάσιμο έγγραφο. Ένας αναγνώστης χωρίς όραση λαμβάνει την περιγραφή στη θέση της εικόνας, και αυτό είναι το σύνολο όσων λαμβάνει. Το «Γράφημα» δεν είναι περιγραφή· το «Τριμηνιαία έσοδα ανά περιοχή, με την ανατολική περιοχή υψηλότερη στο Γ3 τρίμηνο» είναι
Lib.RegisterFigure('Exploded view of the gearbox assembly');
Lib.AddImageFromFile('gearbox.png', 0); // becomes a tagged Figure
Lib.RegisterDecoration; // meaningless rule
Lib.AddImageFromFile('divider.png', 0); // drawn inside a layout artifact
Πίνακες, κεφαλίδες και πού ζει η απόφαση επανάληψης
Με το bit του πίνακα ενεργό, η DrawTableRows μεταφέρει τον πίνακα, τις γραμμές και τα κελιά του στο δέντρο δομής, ώστε ένας αναγνώστης να μπορεί να πει σε ποια στήλη βρίσκεται μια τιμή αντί να διαβάζει ολόκληρο τον πίνακα ως μια ακολουθία άσχετου κειμένου. Η SetTableHeaderRowCount ονομάζει πόσες από τις πρώτες γραμμές είναι κεφαλίδες· αυτές οι γραμμές γράφονται ως κελιά κεφαλίδας που φέρουν εμβέλεια στήλης, που είναι ακριβώς αυτό που επιτρέπει σε έναν αναγνώστη να ανακοινώνει την επικεφαλίδα της τιμής στην οποία βρίσκεται ο χρήστης
Οι γραμμές κεφαλίδας που ονομάζονται έτσι μένουν εκεί που είναι. Η επανάληψή τους στην κορυφή κάθε σελίδας είναι μια απόφαση διάταξης, και παραμένει τέτοια: η DrawTaggedTableRows δέχεται ένα όρισμα RepeatHeaderRows ακριβώς για αυτόν τον σκοπό. Το να παραμένουν τα δύο διαχωρισμένα αποφεύγει το δέντρο δομής να αποκτά δεύτερο αντίγραφο της κεφαλίδας για κάθε αλλαγή σελίδας, που είναι αυτό που θα παρήγαγε μια αυτόματη επανάληψη
var
TableID: Integer;
begin
TableID := Lib.CreateTable(40, 3);
Lib.SetTableHeaderRowCount(TableID, 1); // row 1 is the header band
Lib.SetTableCellContent(TableID, 1, 1, 'Part');
Lib.SetTableCellContent(TableID, 1, 2, 'Torque');
Lib.SetTableCellContent(TableID, 1, 3, 'Unit');
// ... fill the data rows ...
// Draw rows 1..40 into a 600pt band, repeating one header row per page
Lib.DrawTaggedTableRows(TableID, 72, 150, 600, 1, 40, 1);
end;
Συνδυασμός αυτόματης και χειροκίνητης επισήμανσης
Η αυτόματη επισήμανση στέκεται στο πλάι μέσα σε ένα tag που ανοίχτηκε με το χέρι. Μέρος ενός εγγράφου μπορεί να περιγραφεί από τον κώδικά σας και το υπόλοιπο να αφεθεί στη βιβλιοθήκη, χωρίς τα δύο να ενσωματώνονται το ένα μέσα στο άλλο — που είναι η διευθέτηση που θέλουν τα περισσότερα πραγματικά έγγραφα. Η σελίδα εξωφύλλου και το μπλοκ υπογραφής έχουν δομή που καταλαβαίνετε μόνο εσείς· οι διακόσιες σελίδες σώματος κειμένου ανάμεσα δεν την έχουν
Δύο κανόνες ασφαλείας κρατούν την έξοδο καθαρή. Τίποτα δεν επισημαίνεται μέσα σε artifact, επειδή το περιεχόμενο που μαρκαρίζεται ως artifact δεν πρέπει να φέρει κανένα στοιχείο δομής. Και το κενό κείμενο δεν ανοίγει κανένα στοιχείο, οπότε ένα παραπεταμένο DrawText με κενή συμβολοσειρά δεν μπορεί να παράξει στοιχείο δομής που ένας αναγνώστης θα ανακοινώσει ως κενό. Και τα δύο είναι ο τύπος ελαττώματος που τα χειροκίνητα tagged έγγραφα συσσωρεύουν αθόρυβα και που ένας validator αναφέρει μαζικά μήνες αργότερα
Τι δεν αποφασίζει ακόμα για εσάς η αυτόματη επισήμανση
Σειρά ανάγνωσης πέρα από τη σειρά σχεδίασης, σημασιολογικοί ρόλοι που δεν είναι παράγραφος, τίτλος, εικόνα ή πίνακας, και δηλώσεις γλώσσας. Η αυτόματη επισήμανση αναθέτει δομή με τη σειρά που σχεδιάζεται το περιεχόμενο — αν ο κώδικας διάταξής σας σχεδιάζει την πλευρική μπάρα πριν από το σώμα, αυτή είναι η σειρά που καταγράφει το δέντρο. Για έγγραφα όπου η οπτική σειρά και η σειρά ανάγνωσης διαφέρουν πραγματικά, το χειροκίνητο API επισήμανσης παραμένει το σωστό εργαλείο, και η ανάλυση της δομής προσβασιμότητας και tagged PDF καλύπτει ρόλους, εμβέλειες και συνδέσεις κεφαλίδων αναλυτικά
Όταν το έγγραφο ολοκληρωθεί, επικυρώστε αντί να υποθέσετε: οι σημειώσεις για το preflight PDF/A και PDF/UA δείχνουν πώς να πάρετε ετυμηγορία πάνω στη δομή που παράξατε, και η ανάλυση της εξαγωγής αναφορών βάσει dataset καλύπτει πού αυτές οι κλήσεις χωράνε σε μια μηχανή αναφορών που παράγει τη διάταξή της από δεδομένα
Το PDFlibPas είναι μια native Pascal βιβλιοθήκη PDF για Delphi, C++Builder και Lazarus χωρίς εξωτερικό PDF runtime, οπότε η προσβάσιμη έξοδος παράγεται από τον ίδιο κώδικα που σχεδιάζει το έγγραφο — δείτε τη σελίδα προϊόντος PDFlibPas για το πλήρες API και τη λίστα πλατφορμών