Το HotPDF εξάγει μια σελίδα οποιουδήποτε φορτωμένου εγγράφου PDF σε αυτόνομη σήμανση SVG με μία μόνο κλήση, την BuildLoadedPageSVG, η οποία επιστρέφει το πλήρες έγγραφο SVG ως συμβολοσειρά. Η εξαγόμενη σήμανση μεταφέρει τη γεωμετρία της σελίδας, το κείμενο ως πραγματικά στοιχεία SVG text, ενσωματωμένες ράστερ εικόνες, και την κατάσταση πινελιάς που είχαν καθορίσει οι τελεστές PDF σε κάθε λειτουργία σχεδίασης
Αυτό το τελευταίο σημείο είναι εκεί όπου οι περισσότεροι αυτοσχέδιοι μετατροπείς καταρρέουν σιωπηλά. Η μετατροπή μιας σελίδας PDF σε SVG μοιάζει με πρόβλημα συντεταγμένων, αλλά στην πραγματικότητα είναι πρόβλημα κατάστασης. Το PDF είναι μια μηχανή στοίβας της οποίας η κατάσταση γραφικών αλλάζει καθώς ερμηνεύεται η ροή περιεχομένου· το SVG είναι ένα δηλωτικό δέντρο στο οποίο κάθε στοιχείο φέρει τα δικά του χαρακτηριστικά παρουσίασης. Οτιδήποτε ο ερμηνευτής αποτυγχάνει να αποτυπώσει τη στιγμή που εκπέμπεται ένα στοιχείο απλώς χάνεται από την έξοδο, και η αποτυχία είναι σιωπηλή: παίρνετε έγκυρο SVG που αποδίδει μια σελίδα με λεπτά λάθη
Γιατί μια σελίδα PDF δεν μετατρέπεται απλώς σε SVG;
Τρεις ασυμφωνίες καθιστούν τη μετατροπή μη τετριμμένη, και οι τρεις παράγουν έξοδο που φαίνεται εύλογη μέχρι να τη συγκρίνετε δίπλα-δίπλα με το πρωτότυπο. Η πρώτη είναι ο άξονας y. Ο χώρος χρήστη του PDF μεγαλώνει προς τα πάνω από την κάτω αριστερή γωνία της σελίδας· το SVG μεγαλώνει προς τα κάτω από την πάνω αριστερή γωνία. Μια απλή αναστροφή σε επίπεδο σελίδας διορθώνει τις συντεταγμένες σχεδίασης, αλλά καταστρέφει κάθε γλυφή, επειδή η αναστροφή ολόκληρου του καμβά αντικατοπτρίζει και τις μορφές των γραμμάτων
Η δεύτερη ασυμφωνία είναι η κληρονομικότητα. Στο PDF, τα q και Q ωθούν και αποσύρουν μια κατάσταση γραφικών που περιλαμβάνει πλάτος γραμμής, τερματισμό γραμμής, ένωση γραμμής, όριο μύτης, πίνακα διακεκομμένων γραμμών, φάση διακεκομμένης γραμμής και άλφα. Στο SVG, ένα στοιχείο που δεν ονομάζει ένα χαρακτηριστικό το κληρονομεί από μια πρόγονη ομάδα, κάτι που είναι εντελώς διαφορετικός κανόνας εμβέλειας. Ένας εξαγωγέας που παρακολουθεί μόνο τον τρέχοντα πίνακα μετασχηματισμού και ξεχνά την κατάσταση πινελιάς επιτρέπει στην αποκατεστημένη κατάσταση μετά από ένα Q να διαρρεύσει στα στοιχεία που ακολουθούν
Το τρίτο είναι ότι το PDF εκφράζει αρκετά πράγματα με σύμβαση αντί με τιμή. Οι τερματισμοί και οι ενώσεις γραμμών είναι ακέραιοι, το μηδενικό πλάτος γραμμής σημαίνει μια λεπτή γραμμή σε επίπεδο συσκευής αντί για αόρατη γραμμή, και οι παραλλαγές με αστερίσκο των τελεστών ζωγραφικής αλλάζουν τον κανόνα περιέλιξης αντί για το χρώμα. Καθεμιά από αυτές απαιτεί μετάφραση, όχι αντιγραφή
Μία κλήση για τη συνηθισμένη περίπτωση
Για τη συνηθισμένη εργασία εξαγωγής σελίδων για ένα πρόγραμμα προβολής ιστού, ένα εργαλείο σύγκρισης ή μια παράδοση σχεδίασης, η επιφάνεια API είναι μία συνάρτηση. Η BuildLoadedPageSVG δέχεται έναν μηδενοβασισμένο δείκτη σελίδας για το τρέχον φορτωμένο έγγραφο και επιστρέφει το έγγραφο SVG ως AnsiString:
var
Pdf: THotPDF;
I: Integer;
Svg: AnsiString;
Output: TFileStream;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('statements.pdf', '') <= 0 then
Exit; // Η LoadFromFile επιστρέφει τον αριθμό σελίδων
for I := 0 to Pdf.LoadedPageCount - 1 do
begin
Svg := Pdf.BuildLoadedPageSVG(I);
if Length(Svg) = 0 then
Continue;
Output := TFileStream.Create(Format('page-%d.svg', [I + 1]), fmCreate);
try
Output.WriteBuffer(Svg[1], Length(Svg));
finally
Output.Free;
end;
end;
finally
Pdf.Free;
end;
end;
Η ίδια εξαγωγή εκτίθεται από το εργαλείο γραμμής εντολών του HotPDF ως η εντολή του export-svg, που είναι χρήσιμη σε αγωγούς κατασκευής και σενάρια οπισθοδρόμησης όπου θέλετε μια αναπαράσταση σελίδας συγκρίσιμη σε επίπεδο κειμένου χωρίς να γράψετε καθόλου Pascal. Επειδή το SVG είναι κείμενο, αποτελεί φυσικό συνοδό της ράστερ διαδρομής που περιγράφεται στο απόδοση μιας σελίδας PDF σε bitmap: το bitmap σας λέει πώς φαίνεται η σελίδα, το SVG σας λέει από τι αποτελείται
Πώς αντιστοιχίζεται το κείμενο PDF σε στοιχεία κειμένου SVG;
Το HotPDF συνθέτει την αλυσίδα του πίνακα κειμένου ως πρόθεμα επί CTM επί πίνακα κειμένου επί αναστροφή γλυφής, όπου η αναστροφή γλυφής είναι δεξιός πολλαπλασιασμός με τον matrix(1,0,0,-1,0,0). Αυτός ο δεξιός παράγοντας υπάρχει αποκλειστικά για να ακυρώσει την κάθετη αναστροφή σε επίπεδο σελίδας για τα σχήματα γλυφών, καθώς κείμενο SVG σχεδιασμένο σε ανεστραμμένο τοπικό πλαίσιο θα εμφανιζόταν διαφορετικά ανάποδα. Η τοποθέτηση της διόρθωσης στον πίνακα αντί σε κώδικα ειδικής περίπτωσης σημαίνει ότι περιστραμμένο, κατοπτρικό και λοξό κείμενο βγαίνουν όλα σωστά χωρίς επιπλέον διακλαδώσεις
Η οριζόντια τοποθέτηση χρησιμοποιεί τη σύνταξη πολλαπλών τιμών x του στοιχείου SVG text, μία συντεταγμένη ανά χαρακτήρα, συσσωρευμένη από κάθε προχώρημα γλυφής συν το διάστημα χαρακτήρων Tc και το διάστημα λέξεων Tw που ίσχυαν εκείνη τη στιγμή. Η οριζόντια κλιμάκωση Tz ενσωματώνεται στις στήλες a και c του πίνακα κειμένου αντί να εκπέμπεται ξεχωριστά, ώστε ένα πρόγραμμα προβολής που αγνοεί εξωτικά χαρακτηριστικά κειμένου να τοποθετεί και πάλι κάθε γλυφή εκεί όπου την είχε το PDF. Κείμενο που παράγεται μέσω σύνθετης διαμόρφωσης, το οποίο καλύπτεται στη διαμόρφωση κειμένου σύνθετων γραφών, ακολουθεί την ίδια διαδρομή, επειδή ο διαμορφωτής έχει ήδη επιλύσει τις συστάδες σε τοποθετημένες γλυφές τη στιγμή που ερμηνεύεται η ροή περιεχομένου
Περιστροφή και εικόνες: δύο αναστροφές που εύκολα μπερδεύονται
Μια σελίδα με μη μηδενική καταχώριση /Rotate χρειάζεται έναν προμετασχηματισμό που αποτελείται από μια αναστροφή ως προς το περιστραμμένο ύψος καμβά και μια περιστροφή εκφρασμένη σε χώρο απεικόνισης με y προς τα πάνω. Οι τρεις πίνακες περιστροφής είναι (0,-1,1,0,0,W) για 90 μοίρες, (-1,0,0,-1,W,H) για 180 και (0,1,-1,0,H,0) για 270, με τα W και H να είναι οι διαστάσεις της σελίδας πριν την περιστροφή. Η χειροκίνητη παραγωγή αυτών προκαλεί σφάλματα προσήμου σε ακριβώς τρία σημεία, γι' αυτό ο εξαγωγέας τους συνθέτει μέσω της ίδιας ρουτίνας πολλαπλασιασμού πινάκων που χειρίζεται κάθε άλλο μετασχηματισμό
Οι ενσωματωμένες εικόνες χρειάζονται τη δική τους αναστροφή, επειδή ο χώρος εικόνας του PDF τοποθετεί την πρώτη γραμμή δείγματος στο πάνω άκρο του μοναδιαίου τετραγώνου, ενώ το στοιχείο SVG image φέρει τοπικό πλαίσιο με y προς τα κάτω. Ο εκπεμπόμενος μετασχηματισμός είναι επομένως το CTM δεξιά πολλαπλασιασμένο με το matrix(1,0,0,-1,0,1). Αν αυτό γίνει λάθος, παράγονται κάθετα ανεστραμμένες φωτογραφίες σε μια κατά τα άλλα τέλεια σελίδα, ένα ελάττωμα που ένας αναθεωρητής εντοπίζει αμέσως, αλλά μια αυτοματοποιημένη δοκιμή συχνά όχι
Τι διατηρεί πραγματικά η συσκευή κατάστασης γραφικών;
Το HotPDF προωθεί τους τελεστές κατάστασης πινελιάς w, J, j, M και d μέσω ξεχωριστής προαιρετικής διεπαφής συσκευής, ώστε η πιστότητα πινελιάς να προστεθεί χωρίς αλλαγή του vtable της υπάρχουσας συσκευής περιεχομένου και χωρίς να σπάσει η δυαδική συμβατότητα για κώδικα που έχει χτιστεί με παλαιότερες εκδόσεις. Συγκεκριμένα, το εξαγόμενο SVG λαμβάνει μεταφρασμένες λέξεις-κλειδιά αντί για ακατέργαστους ακέραιους PDF:
// Οι ακέραιες απαριθμήσεις PDF γίνονται χαρακτηριστικά λέξεων-κλειδιών SVG
// line cap 0, 1, 2 -> butt, round, square
// line join 0, 1, 2 -> miter, round, bevel
//
// Το μηδενικό πλάτος γραμμής σημαίνει λεπτή γραμμή σε επίπεδο συσκευής στο
// PDF, οπότε ο εξαγωγέας εκπέμπει vector-effect="non-scaling-stroke" για
// να διατηρήσει την πινελιά ορατή και κοντά σε ένα pixel συσκευής πλάτος
// μετά το CTM
//
// f* B* b* επιλέγουν τον κανόνα άρτιου-περιττού και εκπέμπουν
// fill-rule="evenodd", ενώ τα f B b διατηρούν την προεπιλεγμένη περιέλιξη
// nonzero του SVG
Η αποκατάσταση κατάστασης σε ένα Q καλύπτει μαζί την αδιαφάνεια, το πλάτος γραμμής, τον τερματισμό, την ένωση, το όριο μύτης, τον πίνακα διακεκομμένων γραμμών και τη φάση διακεκομμένης γραμμής. Τα εμφωλευμένα Form XObjects αποτυπώνουν και αποκαθιστούν το ίδιο πλήρες σύνολο στα όριά τους, ώστε ένα διακεκομμένο περίγραμμα που ορίζεται μέσα σε μια σφραγίδα να μην μπορεί να διαρρεύσει το μοτίβο του στο περιεχόμενο σελίδας που ακολουθεί. Αν ήδη παρακολουθείτε τη συμπεριφορά αποκοπής και CTM για άλλους λόγους, πρόκειται για το ίδιο μοντέλο κατάστασης που εμφανίζεται στην εισαγωγή διανυσματικών EMF και WMF, εκτελούμενο προς την αντίθετη κατεύθυνση
Όρια που αξίζει να γνωρίζετε πριν το διανείμετε
Ο εξαγωγέας είναι ειλικρινής ως προς το εύρος του, και το να μάθετε τα όριά του εκ των προτέρων κοστίζει λιγότερο από το να τα ανακαλύψετε στην παραγωγή. Το χρώμα φτάνει στη συσκευή SVG μέσω των τελεστών rg, RG, g και G. Γεμίσματα που έχουν καθοριστεί μέσω ενός χρωματικού χώρου συν scn, με τον τρόπο που ζωγραφίζονται τα χρώματα Separation, DeviceN και ICCBased, δεν φτάνουν στη συσκευή ως επιλυμένη τριάδα RGB, οπότε σελίδες που χρησιμοποιούν σημειακά χρώματα με αυτόν τον τρόπο εξάγουν τη γεωμετρία τους αλλά όχι αυτά τα χρώματα. Για πηγές προσανατολισμένες στην εκτύπωση, ράστερ αποδώστε τις ή επιπεδοποιήστε πρώτα τα σημειακά χρώματα· το ίδιο το μοντέλο ζωγραφικής καλύπτεται στην απόδοση σημειακών χρωμάτων Separation και DeviceN
Δύο μικρότερες σημειώσεις εξοικονομούν χρόνο εντοπισμού σφαλμάτων. Τα δεκαεξαδικά χρωματικά κυριολεκτικά εκπέμπονται με κεφαλαία, οπότε μια δοκιμή που ελέγχει το #ff0000 αποτυγχάνει έναντι ενός απολύτως σωστού #FF0000. Και η συσκευή SVG μετράται με αναφορές μέσω της διεπαφής της, που σημαίνει ότι η απελευθέρωσή της είναι θέμα να αφήσετε τη διεπαφή να βγει εκτός εμβέλειας αντί να καλέσετε Free στο αντικείμενο, μια διάκριση που έχει σημασία αν επεκτείνετε τη συσκευή για να εκπέμπει τη δική σας σήμανση παράλληλα με το περιεχόμενο της σελίδας
Η εξαγωγή SVG συνδυάζεται φυσικά με τη δομική σύγκριση όταν χρειάζεται να ξέρετε αν ένα δημιουργημένο έγγραφο πράγματι άλλαξε ανάμεσα σε δύο εκδόσεις. Το ευρύτερο εργαλειοκιτίο γύρω από τα φορτωμένα έγγραφα, από την απόδοση ως την επεξεργασία και την εξαγωγή, τεκμηριώνεται στη σελίδα του εξαρτήματος HotPDF PDF για Delphi