Το HotPDF σχεδιάζει διανυσματικά γραφικά χτίζοντας μια διαδρομή στην τρέχουσα σελίδα και μετά ζητώντας να βαφτεί. Δεν υπάρχει ενδιάμεσο βήμα ψηφιογραφικής εικόνας. Μια γραμμή που σχεδιάζετε με MoveTo και LineTo καταλήγει ως τελεστές διαδρομής PDF μέσα στη ροή περιεχομένου, οπότε παραμένει γνήσιο διάνυσμα: ευκρινής στο 50% του ζουμ, ευκρινής στο 1600%, και κλάσμα του μεγέθους που θα κόστιζε μια ραστεροποιημένη εκδοχή. Για διαγράμματα, γραμμές πινάκων, άξονες γραφημάτων και διακοσμήσεις φορμών, αυτό είναι ακριβώς ό,τι θέλετε, και το API από πίσω είναι αρκετά μικρό ώστε να το μάθετε σε μια καθισιά
Ολόκληρη η επιφάνεια σχεδίασης ζει στο THotPDF.CurrentPage. Ανάμεσα στα BeginDoc και EndDoc ορίζετε χρώμα και πλάτος γραμμής πάνω σε αυτό το αντικείμενο σελίδας, στρώνετε γεωμετρία, και καλείτε έναν τελεστή βαφής για να την οριστικοποιήσετε. Τα τέσσερα αρχέγονα στοιχεία που θα χρησιμοποιείτε περισσότερο είναι τα MoveTo και LineTo για αυθαίρετες διαδρομές, το Rectangle για κουτιά, το Circle για δίσκους, και οι δύο τελεστές βαφής Stroke και Fill
Το σύστημα συντεταγμένων ξεκινά κάτω αριστερά
Αυτό είναι το ένα πράγμα που μπερδεύει όλους όσους έρχονται από τη VCL. Ο TCanvas με τον οποίο ζωγραφίζετε χειριστήρια βάζει την αρχή στην επάνω αριστερή γωνία με το Y να μεγαλώνει προς τα κάτω. Το PDF κάνει το αντίθετο. Το HotPDF μετρά από την κάτω αριστερή γωνία της σελίδας σε σημεία (1/72 της ίντσας), με το Y να αυξάνεται καθώς ανεβαίνετε. Ένα σημείο στο Y := 720 κάθεται κοντά στην κορυφή μιας σελίδας US Letter, που έχει ύψος 792 σημεία, ενώ το Y := 50 κάθεται κοντά στον πάτο. Αν η πρώτη σας σχεδίαση βγει κατοπτρική κατακόρυφα, να γιατί: κώδικας μεταφερμένος από γραφικά οθόνης υποθέτει λάθος κατεύθυνση και ξεφεύγει από την κάτω ακμή
Η ίδια σύμβαση διέπει και το TextOut, οπότε κείμενο και σχήματα μοιράζονται ένα νοητικό μοντέλο μόλις το εσωτερικεύσετε. Σχεδιάστε μια διάταξη αποφασίζοντας πού κάθεται ο πάτος κάθε στοιχείου, όχι η κορυφή, και τα υπόλοιπα ακολουθούν
Διαδρομές: MoveTo, LineTo, Stroke
Μια διαδρομή με περίγραμμα είναι ένα στυλό που σηκώνεται, τοποθετείται και σέρνεται. Το MoveTo σηκώνει το στυλό και ορίζει το σημείο εκκίνησης χωρίς να σημαδεύει τίποτα. Κάθε LineTo επεκτείνει την τρέχουσα διαδρομή σε νέο σημείο. Τίποτα δεν εμφανίζεται στη σελίδα μέχρι να καλέσετε Stroke, που σχεδιάζει τη συσσωρευμένη διαδρομή με το τρέχον χρώμα περιγράμματος και πλάτος γραμμής, και μετά καθαρίζει τη διαδρομή ώστε το επόμενο MoveTo να ξεκινά από την αρχή
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'DrawPaths.pdf';
Pdf.BeginDoc;
// Το πλάτος γραμμής είναι σε σημεία και ισχύει μέχρι να το αλλάξετε.
Pdf.CurrentPage.SetLineWidth(1.5);
Pdf.CurrentPage.SetRGBStrokeColor(clBlack);
// Μια οριζόντια γραμμή κοντά στην κορυφή (το Y μετριέται από τον πάτο).
Pdf.CurrentPage.MoveTo(72, 720);
Pdf.CurrentPage.LineTo(523, 720);
Pdf.CurrentPage.Stroke; // οριστικοποίηση, πριν δεν σχεδιάστηκε τίποτα
// Μια παχύτερη συνδεδεμένη πολυγραμμή: τρία τμήματα σε μία διαδρομή.
Pdf.CurrentPage.SetLineWidth(3);
Pdf.CurrentPage.SetRGBStrokeColor(RGB(30, 90, 200));
Pdf.CurrentPage.MoveTo(72, 640);
Pdf.CurrentPage.LineTo(172, 690);
Pdf.CurrentPage.LineTo(272, 620);
Pdf.CurrentPage.LineTo(372, 680);
Pdf.CurrentPage.Stroke;
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Δύο λεπτομέρειες γλιτώνουν πραγματικό χρόνο αποσφαλμάτωσης. Το πλάτος γραμμής είναι κατάσταση, όχι όρισμα: το SetLineWidth το ορίζει μία φορά και κάθε επόμενο Stroke χρησιμοποιεί εκείνη την τιμή μέχρι να την αλλάξετε ξανά, γι αυτό η παραπάνω πολυγραμμή είναι παχύτερη από τη γραμμή. Και η διαδρομή μηδενίζεται μετά από κάθε Stroke, οπότε ένα ξεχασμένο Stroke σημαίνει ότι η γεωμετρία που στρώσατε με τόση φροντίδα δεν αποδίδεται καθόλου. Αν λείπει ένα σχήμα από την έξοδο, η κλήση βαφής είναι το πρώτο σημείο που κοιτάτε
Οι συντεταγμένες είναι σημεία, και τα σημεία δέχονται κλάσματα. Τα MoveTo και LineTo δέχονται τιμές Single, οπότε μια λεπτή γραμμή στα 0.5 σημεία ή μια θέση στο 72.25 είναι νόμιμη και ουσιαστική, όχι στρογγυλοποιημένη στην πλησιέστερη ακέραιη μονάδα. Αυτή η ακρίβεια μετράει προς δύο αντίθετες κατευθύνσεις. Ένα πλάτος γραμμής κάτω από περίπου 0.5 μπορεί να αποδοθεί ως η λεπτότερη δυνατή γραμμή που εξαρτάται από τη συσκευή, η οποία εξαφανίζεται στην οθόνη και ξαναεμφανίζεται στην εκτύπωση, οπότε μια ορατή γραμμή θέλει πλάτος που ορίζετε επίτηδες και όχι το προεπιλεγμένο. Στο άλλο άκρο, το κούμπωμα των γραμμών πίνακα και του πλέγματος σε ακέραιες συντεταγμένες σημείων εμποδίζει ένα πυκνό πλέγμα να φαίνεται ελαφρώς άνισο εκεί που γειτονικές γραμμές στρογγυλοποιούνται διαφορετικά. Αποφασίστε από την αρχή την απόσταση του πλέγματος σε σημεία και η υπόλοιπη διάταξη την κληρονομεί
Γεμισμένα σχήματα και χρώμα
Τα κλειστά αρχέγονα στοιχεία μπορούν να γεμιστούν αντί να περιγραφούν. Το Rectangle δέχεται θέση και μέγεθος, το Circle δέχεται κέντρο και ακτίνα, και οποιοδήποτε από τα δύο οριστικοποιείται με Fill, που βάφει το εσωτερικό με το τρέχον χρώμα γεμίσματος, ή με Stroke για μόνο περίγραμμα. Το χρώμα γεμίσματος και το χρώμα περιγράμματος είναι ξεχωριστά κομμάτια κατάστασης, που ορίζονται με SetRGBFillColor και SetRGBStrokeColor, και τα δύο δέχονται ένα μοναδικό TColor. Αυτό σημαίνει ότι μπορείτε να επαναχρησιμοποιήσετε απευθείας τις σταθερές χρώματος της Delphi και τον βοηθό RGB
// Rectangle(X, Y, Width, Height): τα X και Y είναι η κάτω αριστερή γωνία.
Pdf.CurrentPage.SetRGBFillColor(RGB(220, 60, 60));
Pdf.CurrentPage.Rectangle(72, 500, 160, 90);
Pdf.CurrentPage.Fill;
// Circle(X, Y, Radius): τα X και Y είναι το κέντρο.
Pdf.CurrentPage.SetRGBFillColor(clNavy);
Pdf.CurrentPage.Circle(420, 545, 45);
Pdf.CurrentPage.Fill;
// Μόνο περίγραμμα: ορίστε χρώμα περιγράμματος και πλάτος, μετά Stroke.
Pdf.CurrentPage.SetLineWidth(2);
Pdf.CurrentPage.SetRGBStrokeColor(clBlack);
Pdf.CurrentPage.Rectangle(72, 400, 160, 60);
Pdf.CurrentPage.Stroke;
Προσέξτε το σχήμα των ορισμάτων στο Rectangle. Είναι θέση συν μέγεθος, X, Y, Width, Height, όχι δύο απέναντι γωνίες. Το TCanvas.Rectangle που ξέρουν οι προγραμματιστές Delphi δέχεται (Left, Top, Right, Bottom), οπότε η μνήμη των δακτύλων θα δώσει στο HotPDF μια δεύτερη γωνία εκεί που εκείνο περιμένει πλάτος και ύψος, και το κουτί βγαίνει σε λάθος μέγεθος. Το ζεύγος (X, Y) είναι η κάτω αριστερή γωνία, σε συνέπεια με την αρχή της σελίδας. Για κύκλο, το (X, Y) είναι το κέντρο και το τρίτο όρισμα είναι η ακτίνα σε σημεία
Μία επιλογή χρώματος που το αρχικό δείγμα έκανε λάθος
Μια παλαιότερη έκδοση αυτού του παραδείγματος έσπερνε χρώματα με Random($FFFFFF) σε κάθε σχήμα. Δείχνει ζωντανό, και είναι λάθος ένστικτο για παραγόμενα έγγραφα. Ένα PDF που χτίζετε από κώδικα είναι συνήθως κάτι που θέλετε και να δοκιμάσετε, και τα τυχαία χρώματα γεμίσματος κάνουν την έξοδο αδύνατο να συγκριθεί από εκτέλεση σε εκτέλεση: μια σύγκριση byte προς byte με ένα γνωστό καλό αρχείο αποτυγχάνει κάθε φορά, χωρίς πραγματικό λόγο. Διαλέξτε ρητά χρώματα. Όταν θέλετε ποικιλία σε μια σειρά σχημάτων, οδηγήστε την από τα δεδομένα σας ή από έναν σταθερό πίνακα παλέτας, ώστε η ίδια είσοδος να παράγει πάντα το ίδιο αρχείο. Ο ντετερμινισμός αξίζει περισσότερο από την πρωτοτυπία όταν το τεχνούργημα περνά μέσα από μια γραμμή έκδοσης
Συνθέτοντας τα αρχέγονα στοιχεία: ένα πλαίσιο επεξήγησης
Κάθε αρχέγονο στοιχείο είναι απλό από μόνο του· το κέρδος φαίνεται όταν μια χούφτα από αυτά συνθέτουν κάτι που χρειάζεται πράγματι μια αναφορά. Μια επεξήγηση, το σχολιασμένο πλαίσιο που δείχνει προς μια εικόνα και την εξηγεί, χρησιμοποιεί όλα όσα καλύφθηκαν ως εδώ: ένα γεμισμένο ορθογώνιο με περίγραμμα, μια γραμμή δείκτη με περίγραμμα, μια κουκκίδα που αγκυρώνει τον δείκτη, και κείμενο διατεταγμένο μέσα στο πλαίσιο με τις ίδιες συντεταγμένες από την κάτω αριστερή γωνία που χρησιμοποιούν τα σχήματα. Το FillAndStroke κερδίζει εδώ τη θέση του, βάφοντας το εσωτερικό και το περίγραμμα μιας διαδρομής σε μία οριστικοποίηση αντί να χτίζει δύο φορές το ορθογώνιο
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'Callout.pdf';
Pdf.BeginDoc;
// 1. Το πλαίσιο: απαλό γέμισμα συν ορατό περίγραμμα, μία διαδρομή, μία οριστικοποίηση.
// Το Rectangle παίρνει κάτω αριστερή γωνία συν μέγεθος, το Y μετριέται από τον πάτο
Pdf.CurrentPage.SetRGBFillColor(RGB(255, 244, 214)); // απαλό κεχριμπαρένιο πάνελ
Pdf.CurrentPage.SetRGBStrokeColor(RGB(180, 130, 40)); // πιο σκούρο πλαίσιο
Pdf.CurrentPage.SetLineWidth(1);
Pdf.CurrentPage.Rectangle(90, 600, 240, 70);
Pdf.CurrentPage.FillAndStroke;
// 2. Ο δείκτης: ένα τμήμα με περίγραμμα από την ακμή του πλαισίου προς
// τα κάτω, προς αυτό που σχολιάζεται
Pdf.CurrentPage.SetLineWidth(1.5);
Pdf.CurrentPage.MoveTo(90, 615); // αριστερή ακμή του πλαισίου
Pdf.CurrentPage.LineTo(66, 546);
Pdf.CurrentPage.Stroke;
// 3. Μια γεμισμένη κουκκίδα αγκυρώνει τον δείκτη στον στόχο του
Pdf.CurrentPage.SetRGBFillColor(RGB(180, 130, 40));
Pdf.CurrentPage.Circle(64, 542, 3);
Pdf.CurrentPage.Fill;
// 4. Η ετικέτα, τοποθετημένη σε σχέση με την κάτω αριστερή γωνία του πλαισίου.
// Κείμενο και σχήματα μοιράζονται ένα σύστημα συντεταγμένων, οπότε οι
// μετατοπίσεις είναι απλή αριθμητική ως προς το (90, 600)
Pdf.CurrentPage.SetFont('Arial', [fsBold], 10);
Pdf.CurrentPage.TextOut(102, 645, 0, 'Check this total');
Pdf.CurrentPage.SetFont('Arial', [], 9);
Pdf.CurrentPage.TextOut(102, 628, 0, 'The rounding rule changed in the');
Pdf.CurrentPage.TextOut(102, 616, 0, 'June release; verify against v2.1');
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Προσέξτε πόσο λίγη διαχείριση κατάστασης χρειάζεται η σύνθεση. Το χρώμα γεμίσματος, το χρώμα περιγράμματος και το πλάτος γραμμής ορίζονται το καθένα αμέσως πριν από το σχήμα που τα χρησιμοποιεί, οπότε κάθε μπλοκ της σχεδίασης διαβάζεται ως αυτοτελής μονάδα και μπορεί να αναδιαταχθεί ή να εξαχθεί σε βοηθό χωρίς να σέρνει μαζί του κρυφή κατάσταση. Τυλίξτε το σε μια διαδικασία που δέχεται το σημείο αγκύρωσης και τις συμβολοσειρές, και έχετε επαναχρησιμοποιήσιμο σχολιασμό διαγράμματος με κόστος σαράντα γραμμές
Πού αποδίδει η διανυσματική σχεδίαση, και πού όχι
Απλώστε το χέρι σε αυτές τις κλήσεις διαδρομών και σχημάτων όταν η γεωμετρία παράγεται: γραμμές πλέγματος και ράβδοι γραφημάτων, οι χαραγμένες γραμμές ενός πίνακα τιμολογίου, πλαίσια επεξήγησης πάνω σε διάγραμμα, ένα σήμα λογότυπου εκφρασμένο ως μια χούφτα διαδρομές. Όλα αυτά κλιμακώνονται χωρίς θόλωμα και προσθέτουν σχεδόν τίποτα στο μέγεθος του αρχείου, επειδή ένα ορθογώνιο είναι λίγοι αριθμοί και όχι χιλιάδες εικονοστοιχεία. Και η άλλη όψη είναι εξίσου ειλικρινής. Αν αυτό που πράγματι έχετε είναι μια φωτογραφία ή ένα στιγμιότυπο οθόνης, σχεδιάστε το ως εικόνα με AddImage και ShowImage· το να ιχνηλατείτε μια ψηφιογραφική εικόνα με διανυσματικές κλήσεις δεν σας αγοράζει τίποτα. Τα ευθύγραμμα τμήματα, τα ορθογώνια και οι κύκλοι παραπάνω σηκώνουν τη μεγάλη πλειοψηφία της πραγματικής δουλειάς αναφορών, και οι τρεις εκλεπτύνσεις που ζητούν στη συνέχεια οι προγραμματιστές, καμπύλες, μοτίβα παύλας και διαφάνεια, κάθονται πάνω στο ίδιο αντικείμενο σελίδας
Καμπύλες, παύλες και διαφάνεια εν συντομία
Οι ελεύθερες καμπύλες επεκτείνουν τον ίδιο μηχανισμό διαδρομών που ήδη έχετε. Το CurveToC(X1, Y1, X2, Y2, X3, Y3) προσαρτά ένα κυβικό τμήμα Bezier από το τρέχον σημείο στο (X3, Y3), λυγίζοντας προς τα δύο σημεία ελέγχου, και οι συντομευμένες παραλλαγές CurveToV και CurveToY καλύπτουν τις περιπτώσεις όπου ένα σημείο ελέγχου συμπίπτει με ένα άκρο. Μια διαδρομή μπορεί να αναμειγνύει ελεύθερα τμήματα LineTo και CurveToC πριν την οριστικοποιήσει ένα μόνο Stroke ή Fill, και έτσι χτίζονται οι στρογγυλεμένες γωνίες και οι ομαλές γραμμές γραφημάτων
Τα διακεκομμένα περιγράμματα είναι κατάσταση, ακριβώς όπως το πλάτος γραμμής. Το SetDash([3, 3], 0) γυρίζει κάθε επόμενο περίγραμμα σε μοτίβο τριών σημείων ναι, τριών σημείων όχι, με τον πίνακα να ορίζει τα μήκη ναι/όχι σε σημεία και το δεύτερο όρισμα να ρυθμίζει τη φάση από την οποία αρχίζει ο κύκλος· το NoDash επιστρέφει το στυλό σε συμπαγή γραμμή. Ορίστε το, περιγράψτε τις γραμμές πλέγματος που το θέλουν, και μηδενίστε το πριν από την επόμενη συμπαγή γραμμή, αλλιώς η παύλα μολύνει σιωπηλά ό,τι ακολουθεί
Η διαφάνεια περνά μέσα από μια ονομασμένη κατάσταση γραφικών και όχι μέσα από όρισμα χρώματος, επειδή το άλφα στο PDF είναι ιδιότητα του λεξικού κατάστασης γραφικών. Καταχωρίστε μία στο έγγραφο με RegisterExtGState, περνώντας άλφα γεμίσματος και άλφα περιγράμματος ανάμεσα στο 0 και το 1, και μετά εφαρμόστε το όνομα που επιστρέφει με CurrentPage.SetGraphicsState· τα γεμίσματα και τα περιγράμματα από εκείνο το σημείο βάφονται με την καταχωρισμένη αδιαφάνεια. Είναι βαρύτερη τελετή από τους ρυθμιστές χρώματος, και αξίζει την πρώτη φορά που μια ράβδος επισήμανσης πρέπει να κάθεται πάνω από κείμενο χωρίς να το κρύβει
Η συνήθεια που απομένει και αξίζει να κρατήσετε είναι η επαλήθευση. Παραγόμενη γεωμετρία μπορεί να περνά στο μηχάνημά σας και να αποτυγχάνει σε εκείνο ενός πελάτη, συνήθως λόγω υποκατάστασης γραμματοσειράς σε όποιο κείμενο αναμειγνύετε ή λόγω μιας υπόθεσης για το μέγεθος σελίδας που δεν ισχύει. Ανοίξτε το τελικό αρχείο σε μερικά επίπεδα ζουμ για να βεβαιωθείτε ότι οι ακμές μένουν καθαρές, και ελέγξτε ότι κάθε σχήμα προσγειώνεται μέσα στο πλαίσιο περιθωρίων που σχεδιάσατε. Με ντετερμινιστικό σχήμα χρωμάτων, αυτός ο έλεγχος μπορεί να αυτοματοποιηθεί απέναντι σε ένα PDF αναφοράς αντί να γίνεται με το μάτι
Οι κλήσεις MoveTo, LineTo, Stroke, Fill και οι κλήσεις χρώματος που παρουσιάζονται εδώ αποτελούν μέρος του HotPDF Delphi Component για Delphi και C++Builder