Κάθε ορατή συμβολοσειρά σε ένα έγγραφο HotPDF προκύπτει μέσω μίας κλήσης: TextOut(X, Y, angle, Text). Το παράδειγμα Hello World την χρησιμοποιεί στην πιο απλή της μορφή, με τη γραμματοσειρά να ορίζεται μία φορά και τα τέσσερα ορίσματα να αφήνονται σε λογικές προεπιλογές. Πέρα από αυτήν την πρώτη σελίδα, τα ίδια τέσσερα ορίσματα σηκώνουν όλο το βάρος της διάταξης. Το τρίτο όρισμα περιστρέφει το κείμενο. Το σύνολο γραμματοσειράς ακριβώς πριν από αυτό καθορίζει το μέγεθος και το στυλ. Και το ζεύγος X, Y, μετρημένο από τη γωνία της σελίδας σε στιγμές (points), είναι το μόνο πράγμα που στέκεται ανάμεσα σε μια καθαρή αναφορά και σε κείμενο που επικαλύπτεται, κόβεται ή γλιστρά μια γραμμή πιο κάτω στον εκτυπωτή κάποιου άλλου. Εδώ είναι που η TextOut αποδεικνύει την αξία της, και όπου οι προεπιλογές παύουν να είναι αρκετές
Η υπογραφή αξίζει να εντυπωθεί στο μυαλό πριν από οτιδήποτε άλλο: τα X και Y είναι Single σε στιγμές (points), το angle είναι ένα Extended σε μοίρες και το Text είναι ένα WideString, οπότε το Unicode περνάει χωρίς ξεχωριστή κλήση. Μια δεύτερη υπερφόρτωση δέχεται ένα PWORD συν ένα μήκος για όταν ήδη κατέχετε κωδικούς γλυφών, αλλά για συνηθισμένες συμβολοσειρές η μορφή WideString είναι αυτή που θα χρησιμοποιήσετε
Το μέγεθος και το στυλ προέρχονται από την SetFont, όχι από την TextOut
Η TextOut δεν έχει παράμετρο μεγέθους. Το μέγεθος, το βάρος, η κλίση, όλα αυτά βρίσκονται στην κλήση SetFont που προηγείται της εκτέλεσης, και παραμένουν σε ισχύ μέχρι η επόμενη SetFont να την αντικαταστήσει. Αυτό είναι το μοναδικό γεγονός που εξηγεί το μεγαλύτερο μέρος της σύγχυσης της πρώτης μέρας: μια γραμμή βγαίνει με έντονη γραφή επειδή τρεις κλήσεις νωρίτερα κάτι έθεσε το [fsBold] και τίποτα δεν το καθάρισε
Pdf.CurrentPage.SetFont('Times New Roman', [], 24);
Pdf.CurrentPage.TextOut(72, 740, 0, 'Quarterly Report'); // 24pt regular
Pdf.CurrentPage.SetFont('Times New Roman', [fsBold], 12);
Pdf.CurrentPage.TextOut(72, 712, 0, 'Revenue'); // 12pt bold
Pdf.CurrentPage.SetFont('Times New Roman', [fsItalic], 11);
Pdf.CurrentPage.TextOut(72, 694, 0, 'figures in thousands'); // 11pt italic
Pdf.CurrentPage.SetFont('Courier New', [fsBold, fsItalic], 10);
Pdf.CurrentPage.TextOut(72, 676, 0, ' +18.4% YoY'); // styles combine
Το δεύτερο όρισμα είναι ένα σύνολο TFontStyles, οπότε το [fsBold, fsItalic] είναι έντονη πλάγια γραφή και το [] είναι απλή. Το μέγεθος είναι σε στιγμές, η ίδια μονάδα με τις συντεταγμένες, το οποίο καθιστά την κατακόρυφη απόσταση εύκολη στην κατανόηση: μια γραμμή 12 στιγμών χρειάζεται περίπου 14 έως 16 στιγμές κατακόρυφου βήματος για να αναπνεύσει, οπότε η μείωση του Y κατά 14 ανά γραμμή είναι ένα λογικό αρχικό διάστιχο. Δεν υπάρχει αυτόματη προώθηση γραμμής. Υπολογίζετε κάθε γραμμή βάσης μόνοι σας, το οποίο είναι κουραστικό για μια παράγραφο αλλά ακριβές για μια φόρμα, όπου κάθε πεδίο κάθεται σε μια σταθερή συντεταγμένη
Δύο πρακτικές σημειώσεις σχετικά με το όνομα της γραμματοσειράς. Επιλύεται έναντι των γραμματοσειρών που είναι εγκατεστημένες στο μηχάνημα κατασκευής, και ό,τι επιστρέφει το λειτουργικό σύστημα είναι αυτό που ενσωματώνεται, επομένως ένα όνομα που επιλύεται στην επιφάνεια εργασίας σας και ένα όνομα που επιλύεται σε έναν διακομιστή κατασκευής (build server) δεν εγγυάται ότι θα είναι η ίδια γραμματοσειρά. Και η γραμματοσειρά πρέπει να καλύπτει τις γραφές της συμβολοσειράς. Ένα τμήμα κυριλλικού ή CJK κειμένου υπό μια γραμματοσειρά μόνο για λατινικά αποδίδεται ως κουτιά γραμμάτων που λείπουν (missing-glyph boxes) χωρίς κανένα σφάλμα, γι' αυτό και η σελίδα Hello World αναζητά μια ευρεία γραμματοσειρά Unicode όταν αναμιγνύει γλώσσες
Το όρισμα angle περιστρέφεται γύρω από την άγκυρα
Το τρίτο όρισμα είναι αυτό που ο περισσότερος κώδικας αφήνει στο μηδέν για πάντα. Αν περάσετε μια μη μηδενική τιμή, η εκτέλεση περιστρέφεται αριστερόστροφα γύρω από τη δική της (X, Y) άγκυρα, την κάτω αριστερή γωνία του κειμένου, κατά τόσες μοίρες. Η ίδια η άγκυρα δεν μετακινείται, επομένως η ίδια συντεταγμένη που τοποθέτησε μια οριζόντια ετικέτα τοποθετεί και την περιστραμμένη δίδυμή της. Μόνο η κατεύθυνση προς την οποία προχωρούν οι γλυφές αλλάζει
Pdf.CurrentPage.SetFont('Arial', [fsBold], 11);
// A vertical axis label down the left margin: 90 degrees reads bottom-to-top.
Pdf.CurrentPage.TextOut(40, 300, 90, 'Units sold');
// A diagonal DRAFT watermark across the page body.
Pdf.CurrentPage.SetFont('Arial', [fsBold], 60);
Pdf.CurrentPage.TextOut(150, 250, 45, 'DRAFT');
// Column headers tilted 60 degrees so long labels fit a narrow table.
Pdf.CurrentPage.SetFont('Arial', [], 9);
Pdf.CurrentPage.TextOut(120, 600, 60, 'Q1 actual');
Pdf.CurrentPage.TextOut(160, 600, 60, 'Q2 actual');
Οι ενενήντα μοίρες είναι η συνηθισμένη περίπτωση, μια ετικέτα που τρέχει στην πλευρά ενός γραφήματος ή ενός τίτλου ράχης. Οι σαράντα πέντε μοίρες χειρίζονται τις κεκλιμένες κεφαλίδες στηλών, το τέχνασμα που επιτρέπει σε μια πλατιά ετικέτα να κάθεται πάνω από μια στενή στήλη χωρίς να χύνεται στις γειτονικές της. Η περιστροφή δεν αλλάζει τον τρόπο ερμηνείας της άγκυρας, πράγμα που μπερδεύει τον κόσμο: μια εκτέλεση 90 μοιρών εξακολουθεί να ξεκινά από το (X, Y) και να μεγαλώνει προς τα πάνω από εκεί, οπότε για να κεντράρετε μια περιστραμμένη ετικέτα, προσαρμόζετε την άγκυρα, όχι τη γωνία. Όταν πολλές περιστραμμένες εκτελέσεις μοιράζονται μια γραμμή βάσης, δώστε τους το ίδιο Y και κάντε βήμα στο X, ακριβώς όπως θα κάνατε βήμα στο Y για στοιβαγμένες οριζόντιες γραμμές
Τοποθέτηση συντεταγμένων χωρίς εικασίες
Οι συντεταγμένες είναι το κομμάτι που επιβιώνει από τον έλεγχο (review) ή τον αποτυγχάνει αθόρυβα. Η HotPDF μετράει από την κάτω αριστερή γωνία της σελίδας, με το Y να αυξάνεται προς τα πάνω, σε στιγμές με αναλογία 72 ανά ίντσα. Μια σελίδα US Letter είναι 612 επί 792 στιγμές. Το A4 είναι 595 επί 842. Επομένως, ένα επάνω περιθώριο μιας ίντσας στο Letter τοποθετεί την πρώτη γραμμή βάσης κοντά στο Y = 792 μείον 72 μείον το μέγεθος της γραμματοσειράς, και όχι σε κάποιον μικρό αριθμό κοντά στην κορυφή. Όποιος έρχεται από συντεταγμένες οθόνης, όπου το Y αυξάνεται προς τα κάτω από το μηδέν, γράφει την πρώτη γραμμή έξω από το κάτω άκρο και περνάει δέκα λεπτά αναρωτώμενος πού πήγε
Αντιμετωπίστε τη διάταξη ως αριθμητική έναντι ονομασμένων αγκυρών αντί για μια στήλη μαγικών αριθμών. Ένα αριστερό περιθώριο, μια τρέχουσα γραμμή βάσης (baseline) που μειώνετε ανά γραμμή και ένα σταθερό διάστιχο (leading) μετατρέπουν ένα μπλοκ ετικετών σε έναν σύντομο βρόχο αντί για έναν τοίχο από κυριολεκτικά στοιχεία (literals):
const
LeftMargin = 72; // 1 inch in
TopBaseline = 720; // first line, ~1 inch down on Letter
Leading = 16; // vertical step between lines
var
Y: Single;
Line: string;
begin
Pdf.CurrentPage.SetFont('Arial', [], 11);
Y := TopBaseline;
for Line in ReportLines do
begin
Pdf.CurrentPage.TextOut(LeftMargin, Y, 0, Line);
Y := Y - Leading;
if Y < 72 then // bottom margin reached
begin
Pdf.AddPage;
Pdf.CurrentPage.SetFont('Arial', [], 11); // font resets on a new page
Y := TopBaseline;
end;
end;
end;
Η προστασία αλλαγής σελίδας είναι η γραμμή που όλοι ξεχνούν πρώτοι και το πεδίο χτυπάει πιο σκληρά. Δεν υπάρχει διάταξη ροής (flow layout) κάτω από την TextOut. Αν μειώσετε κάτω από το κάτω περιθώριο, το κείμενο συνεχίζει να σχεδιάζεται στο περιθώριο, εκτός σελίδας, στο πουθενά, χωρίς προειδοποίηση. Οπότε παρακολουθείτε το Y μόνοι σας, καλείτε το AddPage όταν διασχίσει το δάπεδο, και επαναφέρετε τη γραμμή βάσης. Η SetFont μετά την AddPage δεν είναι προαιρετικό γέμισμα: η τρέχουσα γραμματοσειρά δεν επιβιώνει από μια αλλαγή σελίδας, και η πρώτη εκτέλεση στη νέα σελίδα βγαίνει στην προεπιλεγμένη όψη του προβολέα (viewer) εάν την παραλείψετε
Απόσταση χαρακτήρων και λέξεων για προσαρμογή και στοίχιση
Μερικές φορές μια συμβολοσειρά είναι σωστή αλλά έχει λάθος πλάτος: μια κεφαλίδα που πρέπει να εκτείνεται σε έναν σταθερό κανόνα, ένας κωδικός που θα πρέπει να διαβάζεται με πιο ευάερα ψηφία, μια στήλη που χρειάζεται οι τιμές της να ωθηθούν για να στοιχιστούν. Το PDF φέρει δύο τελεστές κατάστασης κειμένου για αυτό, την απόσταση χαρακτήρων (Tc, επιπλέον κενό που προστίθεται μετά από κάθε γλυφή) και την απόσταση λέξεων (Tw, επιπλέον κενό που προστίθεται σε κάθε χαρακτήρα διαστήματος), και οι δύο εκφράζονται σε μονάδες text-space χωρίς κλιμάκωση, ουσιαστικά στιγμές στο τρέχον μέγεθος γραμματοσειράς. Αποτελούν κατάσταση, όχι ορίσματα στην TextOut, οπότε τα ρυθμίζετε, σχεδιάζετε και τα ρυθμίζετε ξανά πίσω
// Letter-space a short heading so it stretches across a rule.
Pdf.CurrentPage.SetCharacterSpacing(4);
Pdf.CurrentPage.SetFont('Arial', [fsBold], 14);
Pdf.CurrentPage.TextOut(72, 740, 0, 'S U M M A R Y');
Pdf.CurrentPage.SetCharacterSpacing(0); // reset before normal body text
// Open up the gaps between words on a single wide line.
Pdf.CurrentPage.SetWordSpacing(6);
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(72, 712, 0, 'Name Department Extension');
Pdf.CurrentPage.SetWordSpacing(0);
Η απόσταση λέξεων δρα μόνο στον χαρακτήρα διαστήματος (κωδικός 32), πράγμα που έχει μια συνέπεια που αξίζει να γνωρίζετε: δεν κάνει τίποτα μέσα σε μια εκτέλεση CJK που δεν έχει διαστήματα ASCII, και αλληλεπιδρά περίεργα με κείμενο κωδικοποιημένο ως δείκτες γλυφών αντί για byte. Για εξόδους πινάκων λατινικών είναι ο φθηνός τρόπος για να διευρύνετε τα κενά χωρίς να πληκτρολογήσετε ξανά τη συμβολοσειρά. Η απόσταση χαρακτήρων είναι το καλύτερο εργαλείο για μια κεφαλίδα που πρέπει να φτάσει σε ένα πλάτος-στόχο, δεδομένου ότι κατανέμει την προσαρμογή ομοιόμορφα σε κάθε γλυφή αντί να τη συγκεντρώνει στα διαστήματα
Η επαναφορά είναι όλη η πειθαρχία. Η απόσταση, όπως και η γραμματοσειρά, αποτελεί μέρος της κατάστασης σχεδίασης της σελίδας, και η κατάσταση παραμένει μέχρι να την αλλάξετε. Προσθέστε απόσταση χαρακτήρων (letter-space) σε μια κεφαλίδα και ξεχάστε να τη μηδενίσετε, και κάθε παράγραφος παρακάτω κληρονομεί το τέντωμα, το οποίο διαβάζεται ως ένα λεπτό, δυσδιάκριτο λάθος που επιβιώνει από έναν απρόσεκτο έλεγχο (proofread) και αποτυγχάνει σε έναν προσεκτικό. Η αξιόπιστη συνήθεια είναι να ορίσετε μια τιμή απόστασης, να σχεδιάσετε την εκτέλεση που τη χρειάζεται, και να τη ρυθμίσετε ξανά στο μηδέν στην επόμενη γραμμή, έτσι ώστε κανένας μετέπειτα κώδικας να μην χρειάζεται να γνωρίζει τι έκανε μια προηγούμενη ενότητα
Έλεγχος της εξόδου εκεί όπου πραγματικά σπάει
Η διάταξη κειμένου αποτυγχάνει στο δεύτερο μηχάνημα, όχι στο πρώτο, οπότε οι έλεγχοι που έχουν σημασία γίνονται μακριά από το γραφείο σας. Ανοίξτε το παραγόμενο αρχείο σε ένα σύστημα χωρίς το σετ γραμματοσειρών προγραμματιστή σας (developer font set) εγκατεστημένο και επιβεβαιώστε ότι οι ενσωματωμένες όψεις εξακολουθούν να αποδίδονται, συμπεριλαμβανομένων των λατινικών με τόνους, οποιωνδήποτε μη λατινικών γραφών και των σημείων στίξης, με ένα πέρασμα αντί για δειγματοληπτικό έλεγχο των εύκολων χαρακτήρων. Επιλέξτε και αντιγράψτε μερικές γραμμές για να επιβεβαιώσετε ότι το κείμενο είναι πραγματικό κείμενο και όχι περιγράμματα (outlines), το οποίο έχει σημασία τη στιγμή που η αναζήτηση ή η εξαγωγή είναι εντός του πεδίου εφαρμογής. Τροφοδοτήστε τη διάταξη με αντιπροσωπευτικά δεδομένα, τη μεγαλύτερη γερμανική ετικέτα και τον ευρύτερο αριθμό, όχι με ένα τακτοποιημένο σύμβολο κράτησης θέσης (placeholder), επειδή η εκτέλεση που ξεχειλίζει ένα πεδίο είναι πάντα αυτή που δεν πληκτρολογήσατε με το χέρι. Και αν η σελίδα πρέπει να προσγειωθεί σε μια προεκτυπωμένη φόρμα, εκτυπώστε ή μετατρέψτε σε raster ένα δείγμα και τοποθετήστε το πάνω από το πρωτότυπο· μια απόκλιση γραμμής βάσης ενός τετάρτου του χιλιοστού είναι αόρατη στην οθόνη και προφανής στο χαρτί
Αν δεν έχετε γράψει ούτε μία σελίδα ακόμα, ξεκινήστε με το παράδειγμα Hello World της HotPDF, το οποίο στήνει το έγγραφο, τη γραμματοσειρά και το σύστημα συντεταγμένων από την κάτω αριστερή γωνία από το οποίο εξαρτώνται όλα τα παραπάνω. Οι κλήσεις TextOut, SetFont και απόστασης που εμφανίζονται εδώ αποτελούν μέρος του HotPDF Component για Delphi και C++Builder