Ένα PDF του οποίου η κεφαλίδα φέρει φόντο διαβάθμισης (gradient) σε στυλ Word ή Excel, όταν αποδιδόταν σε εικόνα, συνήθως επέστρεφε ένα κενό λευκό ορθογώνιο εκεί όπου έπρεπε να βρίσκεται η ανάμειξη χρωμάτων. Ο αποδότης σελίδας του HotPDF υποστηρίζει πλέον τον τελεστή PDF sh (shading - σκίαση) για αξονικές σκιάσεις Τύπου 2 και ακτινικές σκιάσεις Τύπου 3: αξιολογεί τη συνάρτηση της σκίασης κατά μήκος του άξονα διαβάθμισης και σχεδιάζει την ανάμειξη, ενώ οι παλαιότερες εκδόσεις απέρριπταν σιωπηλά τον τελεστή και άφηναν την περιοχή λευκή σαν χαρτί. Οι δύο τύποι σκίασης που καλύπτουν σχεδόν κάθε διαβάθμιση εγγράφου γραφείου υποστηρίζονται, ενώ οι τύποι πλέγματος (mesh) όχι, και αυτό το άρθρο αναφέρει ειλικρινά πού βρίσκεται αυτή η διαχωριστική γραμμή
Γιατί μια διαβάθμιση PDF αποδίδεται ως λευκό πλαίσιο;
Μια διαβάθμιση PDF είναι μια διανυσματική κατασκευή, όχι ένα bitmap που ο αποδότης μπορεί να αντιγράψει (blit). Ένα λεξικό σκίασης (shading dictionary) (ISO 32000-1 §8.7.4.5) περιγράφει τη γεωμετρία — έναν άξονα ή ένα ζεύγος κύκλων στον πίνακα Coords — συν μια συνάρτηση χρώματος, και ο τελεστής sh σχεδιάζει αυτή τη σκίαση σε ολόκληρη την τρέχουσα περιοχή αποκοπής (clip region), το ίδιο μοντέλο γραφικών που εκθέτει το HotPDF όταν σχεδιάζετε διαδρομές και γεμίσματα σε έναν καμβά σελίδας. Ο αποδότης σελίδας του HotPDF διατρέχει τη ροή περιεχομένου τελεστή προς τελεστή, και οποιοσδήποτε τελεστής δεν έχει αντίστοιχη διαδρομή κώδικα παραλείπεται, ώστε η υπόλοιπη σελίδα να συνεχίσει να αποδίδεται. Πριν από την έκδοση 2.335.0, ο τελεστής sh βρισκόταν σε αυτό το παραλειπόμενο σύνολο: μια διαβάθμιση κεφαλίδας ή ολόκληρης σελίδας δεν συνεισέφερε τίποτα στην έξοδο, οπότε το φόντο εμφανιζόταν ως λευκό. Το αρχείο δεν ήταν ποτέ κατεστραμμένο. Ο αποδότης απλώς δεν είχε χειριστή γι' αυτόν τον συγκεκριμένο τελεστή, και ένα λευκό πλαίσιο είναι ακριβώς αυτό που φαίνεται όταν λείπει ένας χειριστής
Η αλυσίδα αξιολόγησης συναρτήσεων πίσω από μια σκίαση
Μια σκίαση δεν μπορεί να σχεδιαστεί μέχρι να αξιολογηθεί η συνάρτησή της, οπότε αυτός ο μηχανισμός έπρεπε να υλοποιηθεί πρώτα. Οι αξονικές σκιάσεις Τύπου 2 και οι ακτινικές σκιάσεις Τύπου 3 φέρουν και οι δύο μια /Function που αντιστοιχίζει μια παραμετρική θέση κατά μήκος της διαβάθμισης σε ένα χρώμα (ISO 32000-1 §7.10), και ο αξιολογητής συναρτήσεων του HotPDF επιλύει τον FunctionType και εκτελεί την αντίστοιχη ενέργεια. Η εκθετική παρεμβολή Τύπου 2 (§7.10.3) υπολογίζει το C0 + t^N * (C1 - C0) με περιορισμό Domain και Range. Οι δειγματοληπτικές συναρτήσεις Τύπου 0 (§7.10.2) διαβάζουν ένα πλέγμα δειγμάτων 8, 16 ή 32 bit και επιλέγουν το πλησιέστερο μέσω του χάρτη Encode, η περίπτωση που καλύπτεται σε βάθος στο ο οδηγός μας για αναζητήσεις δειγματοληπτικών χρωμάτων Τύπου 0. Οι συναρτήσεις συρραφής (stitching functions) Τύπου 3 (§7.10.4) επιλέγουν μια υποσυνάρτηση από τον πίνακα Bounds και ανατρέχουν σε αυτήν. Οι συναρτήσεις αριθμομηχανής PostScript Τύπου 4 (§7.10.5) δεν αξιολογούνται — υποβαθμίζονται ομαλά σε μια αποτυχημένη αξιολόγηση αντί για λάθος χρώμα, σύμφωνα με τη συντηρητική πολιτική που ακολουθεί το HotPDF στη διαδρομή απόδοσης. Αυτός ο αξιολογητής παραδόθηκε στην έκδοση 2.334.0, μία έκδοση πριν από τον ίδιο τον τελεστή, επειδή ο σχεδιαστής σκίασης είναι τόσο καλός όσο και η συνάρτηση από κάτω του
Πώς το HotPDF μετατρέπει μια συνεχή διαβάθμιση σε pixel;
Το HotPDF προσεγγίζει τη συνεχή ανάμειξη με μια πεπερασμένη σειρά από ζώνες συμπαγούς χρώματος. Ο σχεδιαστής σκίασης διατρέχει τον άξονα διαβάθμισης, τον χωρίζει σε έως και 64 ζώνες — λιγότερες όταν ο άξονας είναι μικρός σε pixel συσκευής — αξιολογεί τη συνάρτηση στην παραμετρική θέση κάθε ζώνης και γεμίζει ένα ορθογώνιο κάθετο στον άξονα με ένα συμπαγές πινέλο. Ο συμβιβασμός είναι ο αριθμός των ζωνών έναντι της ομαλότητας: περισσότερες ζώνες παρακολουθούν την ανάμειξη πιο στενά αλλά κοστίζουν περισσότερα γεμίσματα, και το 64 είναι το σκόπιμο όριο. Επειδή ο αριθμός κλιμακώνεται επίσης με το μήκος του άξονα σε pixel συσκευής, η ανάλυση έχει σημασία. Η απόδοση της ίδιας σελίδας σε υψηλότερο DPI επιμηκύνει τον άξονα, οπότε μια μικρή διαβάθμιση αποκτά ζώνες και οι ρίγες της μαλακώνουν μέχρι να επιτευχθεί το όριο
// The shading discretizer uses up to 64 color bands along the gradient
// axis, but never more than the axis is long in device pixels. Rendering
// the same page at a higher DPI lengthens that axis, so a short gradient
// gains bands and the banding softens until the 64-band ceiling is hit.
Thumb := Pdf.RenderLoadedPageToBitmap(PageIndex, 96); // coarser bands
Proof := Pdf.RenderLoadedPageToBitmap(PageIndex, 300); // up to 64 bands
Απόδοση μιας σκιασμένης σελίδας σε bitmap
Το δημόσιο σημείο εισόδου παραμένει αμετάβλητο: το RenderLoadedPageToBitmap λαμβάνει έναν δείκτη σελίδας με βάση το 0 και μια τιμή DPI, επιστρέφει ένα bitmap 24 bit που ανήκει στον καλούντα, και επιστρέφει nil σε περίπτωση αποτυχίας αντί να προκαλέσει σφάλμα (exception), οπότε η υποστήριξη σκίασης είναι διαφανής για τον κώδικα που ήδη έχετε. Μια σελίδα που συνήθως απέδιδε κενή την κεφαλίδα διαβάθμισης, τώρα επιστρέφει το ίδιο bitmap με την ανάμειξη σχεδιασμένη, και δεν απαιτείται καμία αλλαγή στο API για να το αποκτήσετε. Το μόνο πράγμα που αξίζει να θυμάστε είναι η ιδιοκτησία: ο καλών ελευθερώνει (free) το επιστρεφόμενο bitmap. Η πλήρης ροή απόδοσης — ερμηνεία ροής περιεχομένου, ενσωματωμένοι γλύφοι και προσωρινή αποθήκευση σελίδων — καλύπτεται στον οδηγό για την απόδοση σελίδων PDF σε bitmap στο Delphi
var
Pdf: THotPDF;
Bmp: TBitmap;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('quarterly-report.pdf') > 0 then
begin
// Page 1 (zero-based) at 150 DPI. A gradient-filled header that
// used to come back blank now carries its color blend.
Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
if Assigned(Bmp) then
try
Bmp.SaveToFile('page1.bmp');
finally
Bmp.Free;
end;
end;
finally
Pdf.Free;
end;
end;
Ένας απλός έλεγχος παλινδρόμησης (regression guard) προκύπτει από την ίδια κλήση. Αποδώστε τη σελίδα, λάβετε δείγμα από ένα pixel εκεί που ανήκει η ζώνη διαβάθμισης και επιβεβαιώστε ότι δεν είναι πλέον το λευκό του χαρτιού στο οποίο κατέφευγε ο αποδότης — ένας έλεγχος μίας γραμμής που εντοπίζει μια σιωπηλή επιστροφή στην παλιά συμπεριφορά μη-λειτουργίας (no-op)
Bmp := Pdf.RenderLoadedPageToBitmap(0, 150);
if Assigned(Bmp) then
try
// True when the sh operator painted; False if the region fell back to white.
HeaderPainted := Bmp.Canvas.Pixels[Bmp.Width div 2, 8] <> clWhite;
finally
Bmp.Free;
end;
Τι δεν σχεδιάζει το HotPDF: σκιάσεις πλέγματος (mesh) και άκρα αποκοπής
Οι τέσσερις τύποι σκίασης πλέγματος (mesh shading) είναι εκτός πεδίου εφαρμογής, και ένα έγγραφο θα πρέπει να το γνωρίζει αυτό εκ των προτέρων. Τα ελεύθερης μορφής Gouraud τριγωνικά πλέγματα (Τύπος 4), τα Gouraud πλέγματα μορφής πλέγματος (Τύπος 5), τα Coons patch πλέγματα (Τύπος 6) και τα πλέγματα tensor-product patch (Τύπος 7), που ορίζονται στο ISO 32000-1 §8.7.4.5.5 έως §8.7.4.5.8, δεν αποδίδονται. Μια σελίδα που χρησιμοποιεί έναν από αυτούς εξακολουθεί να αποδίδεται, απλώς αυτή η περιοχή παραμένει ως έχει. Δύο ακόμη λεπτομέρειες αξίζει να αναφερθούν ξεκάθαρα: τα ορθογώνια των ζωνών καλύπτουν τη λωρίδα της σκίασης αντί να αποκόπτονται ακριβώς στην τρέχουσα διαδρομή αποκοπής (clip path), οπότε μια διαβάθμιση που καλύπτεται σε ένα στρογγυλεμένο ή ακανόνιστο σχήμα σχεδιάζεται ως η οριοθετούσα λωρίδα της μέχρι να υλοποιηθεί η ακριβής αποκοπή περιοχής σε μεταγενέστερο στάδιο. Το HotPDF προϋποθέτει επίσης ότι η έξοδος της συνάρτησης είναι RGB ή κλίμακα του γκρι (grayscale), οπότε μια σκίαση που έχει δημιουργηθεί σε CMYK ή σε κάποιον ασυνήθιστο χρωματικό χώρο προσεγγίζεται αντί να διαχειρίζεται χρωματικά. Για τα έγγραφα που επεξεργάζονται οι περισσότερες ομάδες Delphi και C++Builder — αναφορές, τιμολόγια, καταστάσεις και παρουσιάσεις που εξάγονται σε PDF — οι αξονικές και ακτινικές σκιάσεις καλύπτουν ουσιαστικά κάθε διαβάθμιση που θα συναντήσετε, και τα δοκίμια σχεδίασης με έντονη χρήση πλέγματος (mesh) είναι η περίπτωση που πρέπει να αντιμετωπίζεται ως προεπισκόπηση και όχι ως τελικό δοκίμιο
Ο αποδότης σελίδας του HotPDF, η υποστήριξη του τελεστή sh που περιγράφεται εδώ και ο αξιολογητής συναρτήσεων Τύπου 0/2/3 από κάτω του παρέχονται ως μέρος του HotPDF Component για Delphi και C++Builder — μια εγγενή βιβλιοθήκη VCL χωρίς εξωτερικές εξαρτήσεις DLL, η οποία καλύπτεται τη δημιουργία, την επεξεργασία, την εξαγωγή κειμένου και την απόδοση σελίδων PDF σε ένα ενιαίο πακέτο