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

Μια σελίδα PDF δεν έχει παραγράφους ούτε πλαίσια κειμένου. Έχει μια λίστα εντολών: σε αυτή τη θέση, με αυτή τη γραμματοσειρά και αυτό το μέγεθος, σχεδίασε αυτούς τους γλύφους. Η αλλαγή κειμένου σημαίνει διαγραφή των εντολών που σχεδιάζουν τη γραμμή και εγγραφή νέων στην ίδια θέση, με την ίδια γραμματοσειρά, το ίδιο μέγεθος και το ίδιο χρώμα. Γι' αυτό η Επεξεργασία PDF επεξεργάζεται μία γραμμή τη φορά και δεν μπορεί να αναδιπλώσει κείμενο: προκύπτει από τον τρόπο που αποθηκεύεται το κείμενο.
Πώς μοιάζει μία γραμμή κειμένου μέσα στο αρχείο
Το περιεχόμενο μιας σελίδας βρίσκεται σε μια ροή περιεχομένου, ένα μικρό πρόγραμμα από τελεστές. Τέσσερις τελεστές κάνουν το μεγαλύτερο μέρος της δουλειάς για το κείμενο: οι BT και ET περικλείουν ένα μπλοκ κειμένου, ο Tf επιλέγει τη γραμματοσειρά και το μέγεθος, ο Td μετακινείται στην επόμενη θέση και ο Tj σχεδιάζει μια συμβολοσειρά. Με μια τυπική γραμματοσειρά η απλούστερη περίπτωση μοιάζει έτσι:
BT /F1 18 Tf 20 150 Td (Hello World) Tj ET
Σημαίνει: επίλεξε τη γραμματοσειρά F1 στα 18 σημεία (pt), πήγαινε στο x 20, y 150 και σχεδίασε Hello World. Ένα PDF που τυπώνεται από το Chrome συνήθως φαίνεται διαφορετικό: οι παρενθέσεις δεν περιέχουν πια χαρακτήρες αλλά αριθμούς γλύφων της γραμματοσειράς, και ο Tm ορίζει τη θέση μία φορά. Παρακάτω είναι η γραμμή Hello World from Georgia από μια σελίδα που εξήχθη από το Chrome, όπου κάθε τέσσερα δεκαεξαδικά ψηφία είναι ένας αριθμός γλύφου:
BT /F4 24 Tf 1 0 0 -1 30 52 Tm <002b0048004f004f00520003003a00520055004f0047000300490055005200500003002a004800520055004a004c0044> Tj ET
Το 002b είναι H, το 0048 είναι e, το 004f είναι l, το 0003 είναι κενό, το 003a είναι W, και ούτω καθεξής. Αυτοί οι αριθμοί έχουν νόημα μόνο μέσα σε αυτή τη μία γραμματοσειρά· δεν είναι Unicode. Όταν αντιγράφετε το κείμενο, το πρόγραμμα προβολής μετατρέπει τους αριθμούς ξανά σε χαρακτήρες με έναν πίνακα αντιστοίχισης που αποθηκεύεται αλλού στο αρχείο.
Από αυτό προκύπτουν δύο πράγματα. Πρώτον, τίποτα στη ροή περιεχομένου δεν λέει «αυτή είναι παράγραφος»: η αλλαγή γραμμής είναι απλώς ένας ακόμη Td ή Tm που μετακινεί τη θέση στην επόμενη γραμμή, και πόσες γραμμές έχει μια παράγραφος πρέπει να συναχθεί από τις θέσεις. Δεύτερον, για να γράψετε έναν νέο χαρακτήρα σε μια γραμμή χρειάζεστε τον αριθμό του χαρακτήρα αυτού σε εκείνη τη γραμματοσειρά, και η γραμματοσειρά συχνά περιέχει μόνο τους γλύφους που χρησιμοποιήθηκαν όταν γράφτηκε το αρχείο. Αυτό είναι το αποτέλεσμα της υποσυνολοποίησης γραμματοσειρών.
Μπορείτε να αναπτύξετε τις ροές με το qpdf:
qpdf --qdf --object-streams=disable in.pdf out.pdf
Ανοίξτε το out.pdf σε επεξεργαστή κειμένου και αναζητήστε Tj για να δείτε κάθε συμβολοσειρά που σχεδιάζεται στη σελίδα. Για το τι άλλο περιέχει ένα PDF, δείτε το Τι περιέχει ένα PDF: αντικείμενα, ροές και ο πίνακας διασταύρωσης αναφορών.
Πώς ο επεξεργαστής ξαναχτίζει μια «γραμμή» από γλύφους
Ο επεξεργαστής πρέπει πρώτα να ομαδοποιήσει τους διάσπαρτους γλύφους σε μια γραμμή στην οποία μπορεί να κάνει κλικ ο χρήστης. Γλύφοι με την ίδια γραμματοσειρά, το ίδιο μέγεθος και το ίδιο χρώμα, των οποίων το κενό από τον προηγούμενο γλύφο δεν ξεπερνά ένα μέγεθος γραμματοσειράς, ανήκουν στο ίδιο τμήμα (run), δηλαδή μια ομάδα γειτονικών γλύφων· μια αλλαγή γραμμής, μια νέα γραμματοσειρά ή ένα νέο χρώμα το τερματίζει. Κείμενο που τρέχει από δεξιά προς τα αριστερά, ή κατακόρυφα, δεν ομαδοποιείται και δεν μπορεί να ανοίξει για επεξεργασία.
Δύο συνέπειες φαίνονται άμεσα. Μια γραμμή που αναμειγνύει δύο γραμματοσειρές, όπως μια κινεζική γραμμή με μια αγγλική λέξη μέσα της, χωρίζεται σε δύο γειτονικά τμήματα στα οποία κάνετε κλικ ξεχωριστά. Το ίδιο συμβαίνει και μετά από μια επεξεργασία: αν το νέο κείμενο χρησιμοποιεί άλλη γραμματοσειρά, η γραμμή γίνεται δύο τμήματα, και η επεξεργασία του ενός αφήνει το άλλο αμετάβλητο.
Επεξεργασία μιας γραμμής: διαγραφή του παλιού κειμένου και μετά εγγραφή του νέου
Η διαγραφή χρησιμοποιεί τη μορφή του εργαλείου «Μαύρισμα κειμένου» που αφορά μόνο το κείμενο: οι γλύφοι μέσα στην περιοχή της γραμμής αφαιρούνται από τη ροή περιεχομένου, οι εικόνες και οι γραμμές μένουν άθικτες και δεν ζωγραφίζεται έγχρωμο πλαίσιο πάνω από το παλιό κείμενο, οπότε η αντιγραφή και η αναζήτηση δεν το βρίσκουν πια. Αλλάζει μόνο το περιεχόμενο της σελίδας· αν το ίδιο κείμενο εμφανίζεται και σε μια σημείωση (annotation) ή στις ιδιότητες του εγγράφου, αυτά δεν επηρεάζονται.
Η εγγραφή προσαρτά μια νέα εντολή κειμένου στο τέλος της ροής περιεχομένου της σελίδας, ξεκινώντας από τη θέση της γραμμής βάσης της αρχικής γραμμής και επαναχρησιμοποιώντας το μέγεθος και το χρώμα της. Αφού αλλάξουμε την παραπάνω γραμμή σε Hello World 2, αυτό που προστίθεται στο τέλος της σελίδας είναι:
q 1 0 0 1 22.5 148.92 cm 0 0 0 rg
/Span <</ActualText <feff00480065006c006c006f00200057006f0072006c006400200032>>> BDC
BT /F4 18 Tf 0 0 Td <002b0048004f004f00520003003a00520055004f00470003> Tj ET
BT /F9 18 Tf 102.18 0 Td (2) Tj ET
EMC
Q
Το πρώτο BT χρησιμοποιεί την αρχική γραμματοσειρά F4 και τους αρχικούς αριθμούς γλύφων, οπότε το Hello World επαναχρησιμοποιείται ακριβώς όπως ήταν. Το «2» δεν υπάρχει στο αρχικό υποσύνολο γραμματοσειράς, γι' αυτό το δεύτερο BT ξεκινά μια νέα τυπική γραμματοσειρά Helvetica (F9) για να το σχεδιάσει. Τα q και Q περιορίζουν τον μετασχηματισμό συντεταγμένων και το χρώμα αυτού του μπλοκ μέσα σε αυτό· ο επεξεργαστής τυλίγει επίσης το αρχικό περιεχόμενο σε ζεύγος q/Q, ώστε μια κατάσταση γραφικών που έμεινε μη ισορροπημένη στο τέλος της αρχικής σελίδας να μην επηρεάσει το νέο κείμενο. Έτσι έμοιαζε ένα τμήμα· οι αριθμοί αλλάζουν από αρχείο σε αρχείο.
Η προσάρτηση στο τέλος έχει τρεις συνέπειες:
- Το νέο κείμενο ζωγραφίζεται τελευταίο, πάνω από όλα τα υπόλοιπα στη σελίδα. Κείμενο που βρισκόταν κάτω από μια εικόνα ή ένα έγχρωμο μπλοκ εμφανίζεται πάνω από αυτό μετά την επεξεργασία.
- Ένα εργαλείο που εξάγει κείμενο με τη σειρά της ροής περιεχομένου (όπως το
pdftotext -raw) διαβάζει την επεξεργασμένη γραμμή τελευταία σε εκείνη τη σελίδα, ενώ η εξαγωγή βάσει θέσης (pdftotext -layout) δεν δείχνει καμία αλλαγή. Η σελίδα φαίνεται ίδια, αλλά η σειρά ανάγνωσης έχει αλλάξει. - Ο επεξεργαστής επισυνάπτει ένα ActualText στο νέο κείμενο, που λέει στο πρόγραμμα προβολής ποιους πραγματικούς χαρακτήρες αντιπροσωπεύουν οι γλύφοι. Ένας γλύφος μπορεί να αντιστοιχεί σε πολλούς χαρακτήρες, και η αναζήτηση μόνο από τον αριθμό του γλύφου επιστρέφει κάποιες φορές έναν χαρακτήρα συμβατότητας (για παράδειγμα η ανάγνωση του 文 ως ριζικού Kangxi ⽂)· το ActualText εξασφαλίζει ότι αυτό που αντιγράφετε είναι αυτό που πληκτρολογήσατε.
Ποια γραμματοσειρά σχεδιάζει το νέο κείμενο
Η επαναχρησιμοποίηση της αρχικής γραμματοσειράς είναι η ασφαλέστερη επιλογή, γιατί τα σχήματα των γλύφων, το βάρος και το πλάτος ταιριάζουν με ό,τι βρίσκεται δίπλα. Το αν μπορεί να επαναχρησιμοποιηθεί εξαρτάται από το αν ο επεξεργαστής μπορεί να πει ποιον κωδικό έχει ένας χαρακτήρας σε εκείνη τη γραμματοσειρά:
- Μια σύνθετη γραμματοσειρά όπως η παραπάνω (Type0, αριθμοί γλύφων δύο byte, κωδικοποίηση Identity-H): ο χαρακτήρας αναζητείται στη γραμματοσειρά για τον αριθμό του γλύφου και χρησιμοποιείται αν βρεθεί. Αν δεν βρεθεί, ο χαρακτήρας δεν υπάρχει στο υποσύνολο.
- Μια απλή γραμματοσειρά ενός byte (TrueType, Type1) με κωδικοποίηση WinAnsi ή MacRoman: η αντιστοίχιση από χαρακτήρα σε byte είναι σταθερή και τα πλάτη προέρχονται από τον πίνακα πλατών του αρχείου.
- Μια γραμματοσειρά με προσαρμοσμένη κωδικοποίηση (Differences) ή που βασίζεται στην ενσωματωμένη κωδικοποίηση της γραμματοσειράς: δεν υπάρχει αξιόπιστη αντιστοίχιση, οπότε ο επεξεργαστής δεν μαντεύει και πηγαίνει σε εφεδρική γραμματοσειρά, αλλιώς το κείμενο θα βγει παραμορφωμένο.
Όταν ένας χαρακτήρας δεν υπάρχει στην αρχική γραμματοσειρά, χρησιμοποιείται εφεδρική. Τα απλά λατινικά γράμματα χρησιμοποιούν την πλησιέστερη από τις Helvetica, Times και Courier, τυπικές γραμματοσειρές που έχει κάθε πρόγραμμα προβολής, οπότε δεν χρειάζεται να ενσωματωθεί τίποτα. Όλα τα υπόλοιπα, όπως οι κινεζικοί χαρακτήρες, η κάνα, το Χανγκούλ, τα ταϊλανδικά, τα λατινικά με τόνους, τα κυριλλικά και τα ελληνικά, χρησιμοποιούν μια γραμματοσειρά Noto ανοιχτού κώδικα: ο διακομιστής παίρνει τους χαρακτήρες του αιτήματος και κόβει μόνο εκείνους τους γλύφους από την πλήρη γραμματοσειρά με τη βιβλιοθήκη υποσυνολοποίησης HarfBuzz ανοιχτού κώδικα, συνήθως λίγα KB, και το πρόγραμμα περιήγησης τους ενσωματώνει στο αρχείο σας. Η περιφερειακή μορφή ενός κινεζικού χαρακτήρα ακολουθεί τη γλώσσα της διεπαφής: απλοποιημένη, παραδοσιακή, ιαπωνική ή κορεατική.
Οι γλύφοι ενσωματώνονται αντί να γράφεται μόνο ένα όνομα γραμματοσειράς, επειδή μια γραμματοσειρά που αναφέρεται μόνο με το όνομά της αντικαθίσταται από όποια εφεδρική διαλέξει κάθε πρόγραμμα προβολής, και το βάρος μπορεί να διαφέρει από πρόγραμμα σε πρόγραμμα· όταν ενσωματωθεί, κάθε πρόγραμμα προβολής δείχνει τα ίδια σχήματα.
Γιατί μία γραμμή τη φορά
Ο επεξεργαστής δεν έχει μηχανή διάταξης. Κάθε θέση γλύφου είναι σταθερή στο αρχείο· το νέο κείμενο απλώς τοποθετείται προς τα δεξιά από το σημείο εκκίνησης με τα πλάτη της γραμματοσειράς, χωρίς λογική «αναδίπλωσης στο άκρο», και τίποτα μετά από αυτό δεν μετακινείται. Αν μακρύνετε μια γραμμή, οι επιπλέον χαρακτήρες συνεχίζουν προς τα δεξιά, και ό,τι ξεπερνά το άκρο της σελίδας δεν φαίνεται. Για να ξαναγράψετε μια παράγραφο ή να προσθέσετε γραμμές σε έναν πίνακα χρειάζεται νέα διάταξη, δηλαδή επιστροφή στο αρχείο προέλευσης από το οποίο φτιάχτηκε το PDF.
Τα πλάτη είναι επίσης μόνο τα πλάτη προώθησης της ίδιας της γραμματοσειράς, δηλαδή η απόσταση που προχωρά η γραφή μετά από κάθε γλύφο, χωρίς kerning και χωρίς αντικατάσταση γλύφων. Κείμενο που δεν χρειάζεται διαμόρφωση κειμένου (text shaping: επιλογή και τοποθέτηση γλύφων ανάλογα με τα συμφραζόμενα), όπως τα λατινικά, τα κυριλλικά, τα ελληνικά και οι κινεζικοί χαρακτήρες, διατάσσεται σωστά. Οι τόνοι των ταϊλανδικών χρειάζονται τοποθέτηση γλύφων για να κάτσουν στη σωστή θέση, κάτι που ο επεξεργαστής δεν κάνει, γι' αυτό μπορεί να βγουν εκτός θέσης. Τα αραβικά χρειάζονται μορφές γλύφων που εξαρτώνται από το περιβάλλον και διάταξη από δεξιά προς τα αριστερά, τα εβραϊκά χρειάζονται διάταξη από δεξιά προς τα αριστερά, και οι ινδικές γραφές χρειάζονται συνδυασμό συμφώνων και φωνηεντικών σημείων σε γλύφους· όλα αυτά απαιτούν πλήρη διαμόρφωση κειμένου, που ο επεξεργαστής δεν κάνει σήμερα, γι' αυτό η πληκτρολόγησή τους απορρίπτεται αντί να παραχθούν λανθασμένοι χαρακτήρες.
Δύο ακόμη όρια προέρχονται από το ίδιο το αρχείο. Το περιεχόμενο μιας σαρωμένης σελίδας είναι μία εικόνα χωρίς τελεστές κειμένου, οπότε δεν υπάρχει τίποτα να διαγραφεί ή να αλλάξει. Αφού επεξεργαστείτε ένα αρχείο με ψηφιακή υπογραφή, το αρχικό περιεχόμενο που προστάτευε η υπογραφή έχει αλλάξει και η υπογραφή δεν ισχύει πια.
Ελέγξτε το μόνοι σας
Μπορείτε να δείτε τις αλλαγές που περιγράφηκαν παραπάνω σε ένα αρχείο που κατεβάσατε, με τρεις εντολές:
pdftotext -raw edited.pdf - # εξαγωγή με τη σειρά της ροής περιεχομένου: το παλιό κείμενο λείπει, η επεξεργασμένη γραμμή έρχεται τελευταία
pdffonts edited.pdf # λίστα γραμματοσειρών: οι αρχικές που επαναχρησιμοποιήθηκαν και το νέο ενσωματωμένο υποσύνολο
qpdf --qdf --object-streams=disable edited.pdf edited.qdf # ανάπτυξη της ροής περιεχομένου· το προστιθέμενο μπλοκ BT ... ET είναι στο τέλος
Συνεχίστε την ανάγνωση
- Γιατί η υποσυνολοποίηση γραμματοσειρών σπάει την επεξεργασία αλλά όχι την ανάγνωση: γιατί η αρχική γραμματοσειρά μπορεί να μην έχει έναν χαρακτήρα και τι συμβαίνει όταν δεν τον έχει.
- Τι περιέχει ένα PDF: αντικείμενα, ροές και ο πίνακας διασταύρωσης αναφορών: η συνολική εικόνα των ροών περιεχομένου, των αντικειμένων και της δομής του αρχείου.
- Επεξεργασία κειμένου σε PDF online: διορθώστε το χωρίς το αρχείο προέλευσης: πώς χρησιμοποιείται, σε τι ταιριάζει και πότε να επιστρέψετε στο αρχείο προέλευσης.