Το PDFium Component μετατρέπει ένα PDF σταθερής διάταξης σε σημασιολογικό μοντέλο που μπορεί να αναδιαταχθεί, χρησιμοποιώντας την BuildReflowDocument, και εξάγει εκείνο το μοντέλο ως αυτόνομο HTML μέσω της ToHtml. Οι επικεφαλίδες παραμένουν επικεφαλίδες, τα στοιχεία λίστας παραμένουν στοιχεία λίστας, και οι πίνακες που εντοπίζονται στη σελίδα βγαίνουν ως πραγματική σήμανση πίνακα με κελιά κεφαλίδας και εύρη διατηρημένα. Τίποτα στην έξοδο δεν αναφέρεται σε εξωτερικό σενάριο ή φύλλο στυλ
Ο λόγος για να το θέλετε αυτό είναι ότι μια σελίδα PDF είναι ένα σύνολο τοποθετημένων γλυφών, που είναι ακριβώς λάθος για μια οθόνη κινητού, έναν αναγνώστη οθόνης, ή ένα ευρετήριο αναζήτησης. Κάθε προσπάθεια επίλυσης με εξαγωγή απλού κειμένου χάνει τη δομή που έκανε το έγγραφο αναγνώσιμο, και κάθε προσπάθεια επίλυσης με μετατροπή σελίδων σε εικόνες χάνει το κείμενο εντελώς. Ένα μοντέλο αναδιάταξης κρατά και τα δύο: τις λέξεις και τις σχέσεις ανάμεσά τους
Από πού προέρχεται η σημασιολογική πληροφορία;
Όλα ξεκινούν από την GetStructuredText, τη μοναδική πηγή κειμένου και σημασιολογίας στο εξάρτημα. Όταν το PDF φέρει δέντρο δομής, σημασμένο PDF όπως ορίζεται στην ενότητα 14.7 του ISO 32000-1, το μοντέλο ακολουθεί τη λογική ιεραρχία που κατέγραψε ο παραγωγός. Όταν δεν φέρει, και τα περισσότερα PDF στην πράξη δεν φέρουν, το μοντέλο επιστρέφει στη σειρά φυσικής διάταξης που έχει ήδη υπολογιστεί για σκοπούς σειράς ανάγνωσης
Αυτή η επιλογή διατηρεί ένα σκληρό όριο: κανένας δεύτερος αναλυτής PDF και καμία δεύτερη μηχανή απόδοσης δεν εισάγονται για να απαντήσουν ερωτήσεις που η υπάρχουσα μπορεί ήδη να απαντήσει. Ο μηχανισμός σειράς ανάγνωσης από κάτω περιγράφεται στα δομημένα μπλοκ κειμένου και σειρά ανάγνωσης, και το μοντέλο αναδιάταξης είναι ένα σημασιολογικό επίπεδο πάνω του και όχι αντικατάστασή του
Κάθε κόμβος καταγράφει από πού προήλθε η πληροφορία του, ώστε ένας καταναλωτής να μπορεί να διακρίνει μια επικεφαλίδα που δήλωσε το έγγραφο από μια επικεφαλίδα που συνήγαγαν οι ευρετικές διάταξης. Αγωγοί ευαίσθητοι στην εμπιστοσύνη πρέπει να διαβάζουν εκείνο το πεδίο αντί να αντιμετωπίζουν όλους τους κόμβους ως εξίσου έγκυρους
Ένα επίπεδο δέντρο, και γιατί δεν είναι δέντρο αντικειμένων
Το μοντέλο είναι ένα ισοπεδωμένο δέντρο προδιάταξης: ένας πίνακας κόμβων όπου κάθε κόμβος φέρει ένα ParentIndex και ένα Depth, αντί για αναδρομική εγγραφή ή γράφημα αντικειμένων με κυριότητα. Σελίδες, επικεφαλίδες, παράγραφοι, λίστες, στοιχεία λίστας, σχήματα, λεζάντες, πίνακες, γραμμές και κελιά ζουν όλα σε εκείνον τον ένα γραμμικό πίνακα
Δύο οφέλη προκύπτουν. Οι καταναλωτές μπορούν να ρέουν τον πίνακα με σειρά χωρίς αναδρομή, κάτι που κάνει την εκπομπή HTML, Markdown ή προβολή δέντρου έναν απλό βρόχο. Και η διάταξη παραμένει φορητή σε Delphi, C++Builder και Free Pascal, που διαφέρουν στον τρόπο που χειρίζονται αναδρομικούς διαχειριζόμενους τύπους σε ένα όριο ABI. Μια αναδρομική εγγραφή δυναμικών πινάκων είναι ακριβώς το είδος κατασκευής που μεταγλωττίζεται παντού και συμπεριφέρεται λεπτά διαφορετικά σε καθεμιά
uses
PDFium;
var
Pdf: TPdf;
Options: TPdfReflowOptions;
Doc: TPdfReflowDocument;
I: Integer;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'report.pdf';
Pdf.LoadDocument;
Options := TPdfReflowOptions.Default;
Options.FullDocument := True;
Options.DetectTables := True;
Options.IncludeCss := True; // ενσωματωμένο μπλοκ στυλ, χωρίς εξωτερικό αρχείο
Options.MaxNodes := 200000; // όριο fail-closed
Options.MaxCharacters := 4000000;
Doc := Pdf.BuildReflowDocument(Options);
for I := 0 to High(Doc.Nodes) do
case Doc.Nodes[I].Kind of
prnkHeading:
Writeln(Format('%sH%d: %s', [StringOfChar(' ', Doc.Nodes[I].Depth),
Doc.Nodes[I].HeadingLevel, Doc.Nodes[I].Text]));
prnkParagraph:
Writeln(Format('%sp: %s', [StringOfChar(' ', Doc.Nodes[I].Depth),
Copy(Doc.Nodes[I].Text, 1, 60)]));
prnkTable:
Writeln(Format('table on page %d', [Doc.Nodes[I].PageNumber]));
end;
Writeln(Format('%d node(s), %d table(s), %d character(s)',
[Length(Doc.Nodes), Doc.TableCount, Doc.CharacterCount]));
finally
Pdf.Free;
end;
end;
Πώς εμποδίζονται οι πίνακες από το να εμφανίζονται δύο φορές;
Ο εντοπισμός πινάκων εκτελείται αφού έχει συλλεχθεί δομημένο κείμενο για μια σελίδα, κάτι που δημιουργεί έναν προφανή κίνδυνο: το ίδιο περιεχόμενο κελιού υπάρχει και στα μπλοκ κειμένου και στον εντοπισμένο πίνακα. Η εκπομπή και των δύο παράγει HTML όπου κάθε πίνακας ακολουθείται από το ίδιο του το περιεχόμενο ξανά ως ελεύθερες παράγραφοι
Ο κανόνας που το επιλύει είναι γεωμετρικός. Όταν ένας εντοπισμένος πίνακας καλύπτει περισσότερο από τη μισή περιοχή ενός μπλοκ κειμένου, ο κόμβος πίνακα αντικαθιστά εκείνο το μπλοκ αντί να προστίθεται σε αυτό. Η ευρετηρίαση κελιών μέσα σε μια γραμμή χτίζεται μετρώντας σε κάδους, ώστε το χτίσιμο του μοντέλου να παραμένει γραμμικό σε κελιά συν γραμμές αντί να ξανασαρώνει κάθε κελί για κάθε γραμμή, κάτι που έχει σημασία σε οικονομικά έγγραφα όπου μία μοναδική σελίδα μπορεί να φέρει εκατοντάδες κελιά
Η εντοπισμένη δομή είναι ειλικρινής ως προς το ότι είναι εντοπισμός. Ένας πίνακας με γραμμές οριοθέτησης αναγνωρίζεται πιο αξιόπιστα από έναν ευθυγραμμισμένο αμιγώς με κενά, και η εμπιστοσύνη του κόμβου το αντικατοπτρίζει. Για περιεχόμενο όπου ένας λάθος πίνακας είναι καλύτερος από κανέναν πίνακα, κρατήστε τον εντοπισμό ενεργό· για αρχειακή μετατροπή όπου ένας λάθος πίνακας είναι χειρότερος, φιλτράρετε βάσει εμπιστοσύνης
Εξαγωγή HTML που παραμένει αυτόνομο
Η ToHtml διασχίζει το μοντέλο που έχει ήδη χτιστεί και ποτέ δεν ξαναεπισκέπτεται το PDFium, οπότε η εξαγωγή δύο φορές δεν κοστίζει τίποτα επιπλέον και δεν μπορεί να παράγει διαφορετικό αποτέλεσμα από το ίδιο μοντέλο. Κείμενο και τιμές χαρακτηριστικών διαφεύγουν ομοιόμορφα, τα επίπεδα επικεφαλίδας περιορίζονται στο εύρος h1 έως h6 που ορίζει πράγματι το HTML, και κελιά κεφαλίδας, RowSpan και ColumnSpan περνούν όπως γράφτηκαν
Το προαιρετικό CSS είναι ένα απλό ενσωματωμένο μπλοκ στυλ. Δεν υπάρχει σενάριο, δεν υπάρχει γραμματοσειρά ιστού και κανένας εξωτερικός πόρος οποιουδήποτε είδους, κάτι που κάνει την έξοδο ασφαλή για ενσωμάτωση σε email, πρόγραμμα προβολής βοήθειας ή στοιχείο ελέγχου προγράμματος περιήγησης σε sandbox:
var
Html: WideString;
Stream: TFileStream;
Bytes: TBytes;
begin
Options := TPdfReflowOptions.Default;
Options.FullDocument := True;
Options.IncludeCss := True;
Options.IncludePageSections := True; // κρατήστε ορατά τα όρια σελίδας
Options.PreserveLineBreaks := False; // αφήστε το πρόγραμμα περιήγησης να αναδιπλώσει παραγράφους
Html := Pdf.BuildReflowDocument(Options).ToHtml;
Bytes := TEncoding.UTF8.GetBytes(string(Html));
Stream := TFileStream.Create('report.html', fmCreate);
try
if Length(Bytes) > 0 then
Stream.WriteBuffer(Bytes[0], Length(Bytes));
finally
Stream.Free;
end;
end;
Το PreserveLineBreaks είναι η επιλογή που αξίζει περισσότερο να σκεφτείτε. Μια αλλαγή γραμμής PDF είναι μια απόφαση στοιχειοθεσίας που έγινε για σταθερό πλάτος σελίδας, οπότε η διατήρησή της σε στενή οθόνη αναπαράγει ακριβώς το πρόβλημα που η αναδιάταξη υπάρχει για να λύσει. Διατηρήστε τις αλλαγές για ποίηση, καταχωρίσεις κώδικα και διευθύνσεις· αφαιρέστε τις για πεζό λόγο
Όρια, ακύρωση και κατάσταση σελίδας
Χαρακτήρες, κόμβοι, πίνακες και κελιά έχουν καθένας ανώτατο όριο, και καθένα ελέγχεται πριν την εκχώρηση και όχι μετά, ώστε ένα κακοσχηματισμένο ή εχθρικό έγγραφο να αποτυγχάνει καθαρά αντί να καταναλώνει μνήμη μέχρι να αποτύχει κάτι άλλο. Το διακριτικό ακύρωσης ελέγχεται σε όρια σελίδας, μπλοκ, πίνακα, γραμμής και κελιού, κάτι που κρατά ανταποκρίσιμη μια ακυρωμένη σάρωση ενός εγγράφου χιλίων σελίδων
Μια συμπεριφορά έχει σημασία ειδικά για εφαρμογές GUI: ολόκληρη η σάρωση εγγράφου εκτελείται μέσα σε ένα εύρος που αποκαθιστά την ενεργή σελίδα, οπότε επιτυχία, αποτυχία ορίου και ακύρωση αφήνουν όλες ανέγγιχτη την τρέχουσα σελίδα του καλούντος. Ένα πρόγραμμα προβολής που επιτρέπει στον χρήστη να εξάγει ενώ κοιτάζει τη σελίδα 340 βρίσκεται ακόμη στη σελίδα 340 μετά
Για τι είναι καλή η αναδιάταξη, και για τι δεν είναι
Η έξοδος αναδιάταξης είναι εξαιρετική είσοδος για ευρετηρίαση αναζήτησης, προσβάσιμες προβολές ανάγνωσης, οθόνη κινητού και μετάπτωση περιεχομένου. Δεν είναι μετατροπέας που διατηρεί την πιστότητα: απόλυτες θέσεις, ακριβείς γραμματοσειρές, διανυσματικό γραφικό υλικό και ακριβής γεωμετρία σελίδας βρίσκονται εκτός σκοπού εκ σχεδιασμού. Όταν μια εργασία χρειάζεται η σελίδα να φαίνεται ίδια, αποδώστε την· όταν χρειάζεται η σελίδα να είναι αναγνώσιμη κάπου αλλού, αναδιατάξτε την
Ειδικά για υποβοηθητική τεχνολογία, το μοντέλο αναδιάταξης συνδυάζεται με τα χαρακτηριστικά ανάγνωσης που περιγράφονται στο χτίσιμο ενός προσβάσιμου αναγνώστη, και έγγραφα που φέρουν γνήσιο δέντρο δομής παράγουν αισθητά καλύτερα μοντέλα, που είναι ένα καλό επιχείρημα για επικύρωση της σήμανσης ανάντη όπως περιγράφεται στην επικύρωση δέντρου δομής PDF/UA
Αναδιάταξη, δομημένο κείμενο, επικύρωση σήμανσης και απόδοση μοιράζονται ένα αντικείμενο εγγράφου σε Delphi, C++Builder και Lazarus· το πλήρες API περιγράφεται στη σελίδα του PDFium Component για Delphi