Όταν μια σελίδα PDF δεν έχει TrimBox, το δραστικό της TrimBox είναι το CropBox της σελίδας, και όταν λείπει κι εκείνο το CropBox, είναι το MediaBox. Το BleedBox και το ArtBox ακολουθούν τον ίδιο κανόνα. Το PDFlibPas, η PDF Library για Delphi, εφαρμόζει αυτή την αλυσίδα προεπιλογών με συνέπεια στα GetPageBox, HasPageBox και CapturePageEx από το v3.539.44, και αγνοεί production boxes τοποθετημένα σε κόμβο /Pages, επειδή το ISO 32000-1 δεν τα αφήνει να κληρονομούνται
Αυτό διαβάζεται σαν υποσημείωση μέχρι να κάνετε imposition μιας δουλειάς. Φανταστείτε ένα εσωτερικό βιβλίου με MediaBox 6.25 × 9.25 in, CropBox στοιχισμένο στο trim των 6 × 9 in, και χωρίς TrimBox, επειδή όποιος το εξήγαγε δεν σκέφτηκε ποτέ να γράψει ένα. Ζητάτε το trim box, παίρνετε το media box αντί γι αυτό, και κάθε κελί στο φύλλο εκτύπωσης σέρνει ένα όγδοο ίντσας bleed και slug στον γείτονά του. Το PDFlibPas είχε ελαττώματα ακριβώς σε αυτή την περιοχή, διορθωμένα στο v3.539.42 και στο v3.539.44, και ο τρόπος που διορθώθηκαν λέει κάτι για το πώς πρέπει να υλοποιούνται τα page-box semantics σε κάθε βιβλιοθήκη PDF
Ποιο box ισχύει όταν μια σελίδα δεν έχει TrimBox;
Η απάντηση είναι μια σταθερή αλυσίδα προεπιλογών από το ISO 32000-1 §14.11.2: το CropBox προεπιλέγεται στο MediaBox, και το BleedBox, TrimBox και ArtBox προεπιλέγεται καθένα στο CropBox. Τίποτα εκτός από το CropBox δεν προεπιλέγεται απευθείας στο MediaBox. Μια σελίδα που ορίζει μόνο MediaBox έχει επομένως πέντε πανομοιότυπα boxes, και μια σελίδα που ορίζει MediaBox συν CropBox έχει τέσσερα boxes ίσα με το CropBox
| Box | BoxType PDFlibPas | Προεπιλογή όταν λείπει | Κληρονομείται από /Pages |
|---|---|---|---|
| MediaBox | 1 | Κανένα, η εγγραφή είναι υποχρεωτική | Ναι |
| CropBox | 2 | MediaBox | Ναι |
| BleedBox | 3 | CropBox | Όχι |
| TrimBox | 4 | CropBox | Όχι |
| ArtBox | 5 | CropBox | Όχι |
Η αλυσίδα δύο βημάτων μετράει επειδή το CropBox μπορεί το ίδιο να κληρονομείται. Το δραστικό TrimBox μιας σελίδας που δεν έχει ούτε TrimBox ούτε δικό της CropBox είναι το CropBox του πλησιέστερου προγόνου που έχει ένα, και σε αποτυχία, το κληρονομημένο MediaBox. Η προδιαγραφή προσθέτει έναν ακόμα κανόνα που ξεχνιέται εύκολα: τα crop, bleed, trim και art boxes δεν πρέπει να εκτείνονται πέρα από το media box, και αν το κάνουν, ανάγονται δραστικά στην τομή τους με εκείνο. Το PDFlibPas αναφέρει κάθε box όπως είναι αποθηκευμένο στο αρχείο, οπότε ένας validator που χειρίζεται αναξιόπιστη είσοδο πρέπει να το περιορίζει μόνος του στο MediaBox
Ποιες ιδιότητες σελίδας μπορεί να κληροδοτήσει ένας κόμβος /Pages;
Ακριβώς τέσσερις: Resources, MediaBox, CropBox και Rotate. Το ISO 32000-1 §7.7.3.4 ορίζει την κληρονομιά ιδιοτήτων, και το Table 30 σημειώνει μόνο εκείνες τις τέσσερις εγγραφές page-object ως κληρονομήσιμες. Το BleedBox, TrimBox και ArtBox ανήκουν στη σελίδα φύλλο. Ένα TrimBox γραμμένο σε κόμβο /Pages δεν είναι κληρονομημένη τιμή· είναι μη πρότυπο κλειδί που ένας συμμορφούμενος reader αγνοεί
Μη πρότυπα αρχεία σαν αυτό υπάρχουν, συνήθως με ένα μόνο TrimBox στον ριζικό κόμβο του page tree ως συντομογραφία για "κάθε σελίδα έχει αυτό το trim". Η συντομογραφία φαίνεται σωστή σε κάθε εργαλείο που περπατά /Parent για κάθε κλειδί, και εκεί είναι το πρόβλημα: το αρχείο πλέον σημαίνει δύο πράγματα ανάλογα με το ποιος το διαβάζει. Ένας reader που ακολουθεί την προδιαγραφή δεν βλέπει TrimBox και χρησιμοποιεί το CropBox, ενώ ένας reader που κληρονομεί τα πάντα βλέπει την τιμή του γονέα. Σε προεκτυπωτική ροή εκείνη η αμφισημία καταλήγει στο φύλλο εκτύπωσης
Οι ροές PDF/X (ISO 15930) βασίζονται στο TrimBox για το τελικό μέγεθος, και τα προφίλ PDF/X απαιτούν κάθε σελίδα να δηλώνει TrimBox ή ArtBox. Ένα box παρκαρισμένο σε κόμβο /Pages δεν πληροί εκείνη την απαίτηση, επειδή το κλειδί δεν φτάνει ποτέ στο object της σελίδας. Το Preflight πρέπει να επισημαίνει τέτοια αρχεία αντί να τα διαβάζει αθόρυβα με τον έναν ή τον άλλον τρόπο
Τι είχε κάνει λάθος το PDFlibPas πριν το v3.539.44;
Το PDFlibPas είχε τρία ξεχωριστά ελαττώματα, όλα στο κενό ανάμεσα σε ό,τι λέει η προδιαγραφή και σε ό,τι έκαναν δύο ανεξάρτητες διαδρομές κώδικα. Το πρώτο διορθώθηκε στο v3.539.42, τα άλλα δύο στο v3.539.44
Production boxes προεπιλέγονταν στο MediaBox κατά τη σύλληψη
Πριν το v3.539.42, η εσωτερική ρουτίνα που προετοιμάζει μια σελίδα για σύλληψη (αντιγράφει κληρονομημένες εγγραφές πάνω στη σελίδα και συμπληρώνει τα λείποντα boxes) έδινε στο BleedBox, TrimBox και ArtBox τις τιμές του MediaBox όταν εκείνα απουσίαζαν. Το CapturePageEx με options 2 έως 4 διαβάζει το οριοθετικό του ορθογώνιο από ακριβώς εκείνες τις συμπληρωμένες εγγραφές, οπότε σε σελίδα που ορίζει μόνο CropBox, η ζήτηση του trim box συνέλλεγε ολόκληρο το media box. Το GetPageBox εφάρμοζε ήδη την προεπιλογή CropBox, και η αναφορά του CapturePageEx έλεγε πάντα ότι το crop box χρησιμοποιείται όταν το ζητούμενο box λείπει· ο κώδικας σύλληψης διαφωνούσε με τους δύο. Από το v3.539.42 τα τρία production boxes προεπιλέγονται στο CropBox της σελίδας, που ως εκείνο το σημείο είναι ήδη πάνω στη σελίδα (δικό της, αντιγραμμένο από πρόγονο, ή συμπληρωμένο από το MediaBox), και μόνο το ίδιο το CropBox υποχωρεί στο MediaBox
Δύο διαδρομές κληρονομιάς, ένας σημασιολογικός κανόνας
Το δεύτερο ελάττωμα ήταν η ίδια η μη πρότυπη κληρονομιά, και το λεπτό σημείο ήταν ότι το PDFlibPas έλυνε τα boxes κατά μήκος δύο ανεξάρτητων διαδρομών. Τα box queries (GetPageBox και HasPageBox) περπατούσαν την αλυσίδα /Parent μέσω ενός βοηθού, και η σύλληψη την περπατούσε μέσω ξεχωριστού τοπικού βοηθού. Και οι δύο κληρονομούσαν κάθε κλειδί, production boxes συμπεριλαμβανομένων. Η διόρθωση μόνο ενός θα παρήγε αντίφαση μέσα σε ένα έγγραφο: με TrimBox πλάτους 180 points στον κόμβο /Pages και CropBox πλάτους 380 points στη σελίδα, το GetPageBox θα ανέφερε ακόμα πλάτος trim 180 ενώ το CapturePageEx έχτιζε φόρμα πλάτους 380. Στο v3.539.44 και οι δύο διαδρομές περιορίζουν το περπάτημα /Parent στα τέσσερα κληρονομήσιμα κλειδιά, τα production boxes διαβάζονται μόνο από το φύλλο, και η παρατημένη εγγραφή γονέα μένει στο αρχείο ανέγγιχτη, ούτε διαγραμμένη ούτε ξαναγραμμένη
Το HasPageBox έχανε άμεσους πίνακες γονέα
Το HasPageBox επιστρέφει 0 όταν η σελίδα δεν έχει box του ζητούμενου τύπου, 1 όταν η σελίδα έχει δικό της box (αποθηκευμένο απευθείας ή μέσω indirect reference), και 2 όταν ένα MediaBox ή CropBox κληρονομείται από πρόγονο. Ο παλιός κώδικας επέστρεφε 2 μόνο όταν η κληρονομημένη τιμή ήταν indirect reference, οπότε κληρονομημένος άμεσος πίνακας επέστρεφε 0. Η διόρθωση χωρίζει την αποαναφορά από το test πίνακα, και οι δύο αναπαραστάσεις επιστρέφουν πλέον 2. Από το v3.539.44, το HasPageBox για BleedBox, TrimBox ή ArtBox μπορεί να επιστρέψει μόνο 0 ή 1
Το μάθημα γενικεύει πολύ πέρα από page boxes. Όταν ένα κομμάτι σημασιολογίας προδιαγραφής έχει δύο σημεία εισόδου υλοποίησης σε μια βιβλιοθήκη, διορθώστε τα μαζί και τεστάρετέ τα ως μήτρα αντί με ένα happy-path αρχείο. Το regression σύνολο του PDFlibPas διασταυρώνει δύο αναπαραστάσεις γονικού box (άμεσο και indirect πίνακα) με τρεις καταστάσεις φύλλου (απόν, άμεσος πίνακας, indirect πίνακας) και τρία capture options (bleed, trim, art), δίνοντας 18 σενάρια, και το καθένα ελέγχει το αποτέλεσμα του query, τα συλληφθέντα όρια, τη νόμιμη κληρονομιά MediaBox και CropBox, και την ανέγγιχτη εγγραφή γονέα
Πώς διαβάζω το δραστικό TrimBox σε Delphi;
Καλέστε GetPageBox(4, Dimension) στην επιλεγμένη σελίδα. Το PDFlibPas εφαρμόζει την αλυσίδα προεπιλογών για εσάς, οπότε το αποτέλεσμα είναι το δραστικό TrimBox είτε η σελίδα έχει είτε όχι. Συνδυάστε το με HasPageBox όταν χρειάζεστε να ξέρετε από πού προήλθε η τιμή, που συνήθως θέλει μια αναφορά preflight
uses
System.SysUtils, PDFlibrary;
const
BOX_CROP = 2;
BOX_TRIM = 4;
DIM_LEFT = 0;
DIM_WIDTH = 2;
DIM_HEIGHT = 3;
DIM_BOTTOM = 5;
function DescribeTrim(Lib: TPDFlib; Page: Integer): string;
var
Source: string;
begin
Lib.SelectPage(Page);
if Lib.HasPageBox(BOX_TRIM) = 1 then
Source := 'own TrimBox'
else if Lib.HasPageBox(BOX_CROP) <> 0 then // 1 = δικό της, 2 = κληρονομημένο
Source := 'defaulted to the CropBox'
else
Source := 'defaulted to the MediaBox';
Result := Format('page %d: trim %.2f x %.2f pt at (%.2f, %.2f), %s',
[Page,
Lib.GetPageBox(BOX_TRIM, DIM_WIDTH),
Lib.GetPageBox(BOX_TRIM, DIM_HEIGHT),
Lib.GetPageBox(BOX_TRIM, DIM_LEFT),
Lib.GetPageBox(BOX_TRIM, DIM_BOTTOM),
Source]);
end;
var
Lib: TPDFlib;
Page: Integer;
begin
Lib := TPDFlib.Create;
try
if Lib.LoadFromFile('interior.pdf', '') = 1 then
for Page := 1 to Lib.PageCount do
Writeln(DescribeTrim(Lib, Page));
finally
Lib.Free;
end;
end.
Τα GetPageBox και SetPageBox δουλεύουν στις τρέχουσες ρυθμίσεις συντεταγμένων του εγγράφου. Τα παραδείγματα εδώ τρέχουν με τις προεπιλογές: αρχή 0 (κάτω αριστερά, κατά το PDF user space) και points ως μονάδα μέτρησης, οπότε η διάσταση Top είναι το πάνω άκρο μετρημένο προς τα πάνω από το κάτω μέρος της σελίδας. Μετά από SetOrigin(1) οι διαστάσεις Top και Bottom μετρώνται προς τα κάτω από την κορυφή της σελίδας, και μετά από SetMeasurementUnits(1) κάθε τιμή επιστρέφει σε χιλιοστά. Το πλάτος και το ύψος δεν εξαρτώνται από την αρχή
Εύρεση production boxes εγκαταλελειμμένων σε κόμβους /Pages
Από το v3.539.44 το box API δεν βλέπει πια TrimBox σε κόμβο /Pages, που είναι το σωστό, αλλά ένα εργαλείο preflight συνήθως θέλει να αναφέρει ένα τέτοιο αρχείο αντί να το διαβάσει αθόρυβα με τον τρόπο της προδιαγραφής. Οι κόμβοι page tree είναι συνηθισμένα objects, οπότε το χαμηλού επιπέδου object API μπορεί να τους βρει: περπατήστε αριθμούς objects μέχρι το GetMaxObjectNumber, διαβάστε τον καθένα με GetObjectToString, και ψάξτε για λεξικό /Pages που κρατά κλειδί production box. Το δεύτερο μισό του ελέγχου είναι το ανά σελίδα test που νοιάζεται το PDF/X, και το HasPageBox απαντά πλέον όπως θα απαντούσε ένας validator PDF/X, επειδή ένα γονικό TrimBox δεν μετράει πια
procedure PreflightTrim(Lib: TPDFlib; Log: TStrings);
const
ProductionKeys: array[0..2] of string = ('/BleedBox', '/TrimBox', '/ArtBox');
var
ObjNum, K, Page, Missing: Integer;
Src: string;
begin
// 1. Production boxes σε κόμβους page tree: μη πρότυπα και αγνοούμενα
for ObjNum := 1 to Lib.GetMaxObjectNumber do
begin
Src := ''; // ελεύθεροι αριθμοί δεν επιστρέφουν κείμενο
Src := string(Lib.GetObjectToString(ObjNum));
if Pos('/Type /Pages', Src) = 0 then
Continue;
for K := Low(ProductionKeys) to High(ProductionKeys) do
if Pos(ProductionKeys[K] + ' ', Src) > 0 then
Log.Add(Format('object %d: %s on a /Pages node is not inheritable',
[ObjNum, ProductionKeys[K]]));
end;
// 2. PDF/X: κάθε σελίδα θέλει το δικό της TrimBox ή ArtBox
Missing := 0;
for Page := 1 to Lib.PageCount do
begin
Lib.SelectPage(Page);
if (Lib.HasPageBox(4) = 0) and (Lib.HasPageBox(5) = 0) then
begin
Inc(Missing);
Log.Add(Format('page %d: no TrimBox or ArtBox', [Page]));
end;
end;
// 3. Προαιρετική επιδιόρθωση: trim 6 x 9 in μέσα σε media box 6.25 x 9.25 in
// (points, αρχή κάτω αριστερά: Left, Top, Width, Height)
if Missing > 0 then
Log.Add(Format('TrimBox written on %d pages',
[Lib.SetPageBoxRange('', 4, 9, 657, 432, 648)]));
end;
Το ταίριασμα κειμένου είναι πρακτικός έλεγχος, όχι parser. Βασίζεται στο PDFlibPas να σειριοποιεί κάθε εγγραφή λεξικού ως κλειδί, ένα κενό και μια τιμή, που ισχύει για objects διαβασμένα πίσω μέσω GetObjectToString. Το βήμα επιδιόρθωσης αξίζει απόφαση αντί για αντανακλαστικό: η παρατημένη γονική τιμή μπορεί κάλλιστα να είναι αυτό που εννοούσε ο συγγραφέας, αλλά επιβεβαιώστε το απέναντι στο job ticket πριν την κάνετε επίσημη. Το SetPageBoxRange με κενό εύρος εφαρμόζει το box σε κάθε σελίδα και επιστρέφει το πλήθος των ενημερωμένων σελίδων. Όταν το υπάρχον box μιας σελίδας είναι indirect πίνακας, που μπορεί να μοιράζεται άλλη σελίδα ή κόμβος /Pages, το SetPageBox δίνει σε εκείνη τη σελίδα νέο άμεσο πίνακα αντί να ξαναγράψει το κοινό object. Ο ορισμός BleedBox, TrimBox ή ArtBox ανεβάζει επίσης ένα ξεκλείδωτο έγγραφο σε PDF 1.3, την έκδοση που εισήγαγε εκείνες τις εγγραφές
Imposition σελίδων πάνω στο TrimBox με CapturePageEx
Το CapturePageEx(Page, 3) γυρνά μια σελίδα σε Form XObject του οποίου το οριοθετικό box είναι το δραστικό TrimBox της σελίδας, και το DrawCapturedPage τοποθετεί εκείνη τη φόρμα σε άλλη σελίδα σε οποιοδήποτε μέγεθος. Από το v3.539.42, το option 3 σε σελίδα χωρίς TrimBox σας δίνει το CropBox, όπως περιγράφει η αναφορά, αντί για το MediaBox με όλο του το slug
Δύο ιδιότητες της σύλληψης πλαισιώνουν τον κώδικα. Η σύλληψη είναι καταστροφική: η συλληφθείσα σελίδα αφαιρείται από το έγγραφο, και το έγγραφο δεν μπορεί ποτέ να πέσει στο μηδέν σελίδες, οπότε προσθέστε το πρώτο φύλλο εξόδου πριν συλλάβετε οτιδήποτε. Η σύλληψη δουλεύει επίσης μόνο μέσα σε ένα έγγραφο, οπότε τραβήξτε πρώτα κάθε είσοδο σε ένα ενιαίο έγγραφο· οι τεχνικές για το collating και interleaving PDF πηγών σε ένα πέρασμα εφαρμόζονται απευθείας
procedure ImposeTwoUp(const InFile, OutFile: string);
var
Lib: TPDFlib;
Captures: array of Integer;
SourceCount, I: Integer;
TrimW, TrimH: Double;
begin
Lib := TPDFlib.Create;
try
if Lib.LoadFromFile(InFile, '') <> 1 then
raise Exception.Create('Cannot open ' + InFile);
SourceCount := Lib.PageCount;
// Δραστικό μέγεθος trim της σελίδας 1 (αυτή η διάταξη υποθέτει ενιαίο trim)
Lib.SelectPage(1);
TrimW := Lib.GetPageBox(4, 2);
TrimH := Lib.GetPageBox(4, 3);
// Προσθήκη και διαστασιολόγηση του πρώτου φύλλου· το NewPage επιλέγει τη νέα σελίδα
Lib.NewPage;
Lib.SetPageDimensions(2 * TrimW, TrimH);
// Κάθε σύλληψη αφαιρεί τη σελίδα 1, οπότε η επόμενη σελίδα πηγής ανεβαίνει
SetLength(Captures, SourceCount);
for I := 0 to SourceCount - 1 do
begin
Captures[I] := Lib.CapturePageEx(1, 3); // 3 = TrimBox
if Captures[I] = 0 then
raise Exception.CreateFmt('Capture of source page %d failed', [I + 1]);
end;
// Απομένει μόνο το φύλλο: δύο κομμένες σελίδες ανά φύλλο, η μία δίπλα στην άλλη
Lib.SelectPage(1);
for I := 0 to SourceCount - 1 do
begin
if (I > 0) and (I mod 2 = 0) then
Lib.NewPage; // ίδιο μέγεθος με το τρέχον φύλλο
// Προεπιλεγμένη αρχή: το Top είναι το πάνω άκρο, μετρημένο από το κάτω μέρος
Lib.DrawCapturedPage(Captures[I], (I mod 2) * TrimW, TrimH, TrimW, TrimH);
end;
Lib.SaveToFile(OutFile);
finally
Lib.Free;
end;
end;
Μια σύλληψη βασισμένη στο trim κόβει οτιδήποτε έξω από το TrimBox, που είναι αυτό που θέλετε για ψηφιακό proof ή διάταξη cut-and-stack. Για φύλλο εκτύπωσης που κόβεται μετά την εκτύπωση, συλλάβτε με option 2 ώστε το bleed να επιβιώσει, και ανοίξτε τα κελιά κατά το πλάτος του bleed. Επειδή η σύλληψη αφαιρεί τις σελίδες πηγής, bookmarks και links που έδειχναν σε εκείνες χάνουν τους στόχους τους, οπότε κάντε imposition σε ξεχωριστό αρχείο εξόδου αντί να επεξεργάζεστε έγγραφο του οποίου την πλοήγηση εξακολουθείτε να χρειάζεστε· το αντικαθιστώντας σελίδες χωρίς να σπάτε bookmarks καλύπτει εκείνη την πλευρά της χειρουργικής σελίδων
Όταν η πηγή πρέπει να μείνει ανέπαφη, το ImportPageAsFormXObject(SourceDocumentID, SourcePage, Options) παίρνει τις ίδιες τιμές option 0 έως 4 (περάστε Lib.SelectedDocument για το τρέχον έγγραφο), αφήνει το page tree της πηγής αμετάβλητο, κανονικοποιεί κληρονομημένη περιστροφή σελίδας μέσα στον πίνακα της φόρμας, και επιστρέφει handle που δέχεται το DrawCapturedPage. Το CapturePageEx δεν αναιρεί το /Rotate, οπότε στραμμένη είσοδος θέλει εκείνο το βήμα πρώτα, και το ισοπέδωση περιστροφής σελίδας χωρίς να σπάτε page boxes δείχνει τι πάθει κάθε box όταν το κάνετε. Μια προσοχή για εισόδους που μπορεί να κουβαλούν production boxes σε κόμβους /Pages: η διαδρομή import λύνει το box της μέσω δικής της αναζήτησης προγόνων, ξεχωριστή από τις δύο διαδρομές που ευθυγραμμίστηκαν στο v3.539.44, οπότε ελέγξτε HasPageBox(4) στη σελίδα πηγής πρώτα και περάστε option 1 (CropBox) όταν επιστρέφει 0. Έτσι το αποτέλεσμα μένει δεμένο με την προδιαγραφή αντί με το πώς τύχαινε να γραφτεί το αρχείο
Σύντομη αναφορά page boxes
- Δραστικό CropBox: το δικό της CropBox της σελίδας, αλλιώς το πλησιέστερο κληρονομημένο CropBox, αλλιώς το δραστικό MediaBox (ISO 32000-1 §14.11.2)
- Δραστικό BleedBox, TrimBox και ArtBox: η δική της εγγραφή της σελίδας φύλλου, αλλιώς το δραστικό CropBox
- Μόνο τα
Resources,MediaBox,CropBoxκαιRotateκληρονομούνται από κόμβους/Pages(§7.7.3.4, Table 30)· production boxes σε κόμβους/Pagesαγνοούνται GetPageBox(BoxType, Dimension): BoxType 1 MediaBox, 2 CropBox, 3 BleedBox, 4 TrimBox, 5 ArtBox· Dimension 0 Left, 1 Top, 2 Width, 3 Height, 4 Right, 5 BottomHasPageBox(BoxType): 0 κανένα box, 1 το δικό της box της σελίδας (άμεσο ή indirect), 2 κληρονομημένο MediaBox ή CropBox (άμεσο ή indirect)CapturePageEx(Page, Options): 0 MediaBox, 1 CropBox με υποχώρηση σε MediaBox, 2 έως 4 BleedBox, TrimBox ή ArtBox με υποχώρηση σε CropBox- Αναβαθμίστε σε v3.539.44 ή νεότερο για συνεπείς προεπιλογές και κληρονομιά σε box queries και σύλληψη
Τα page boxes είναι εκεί όπου οι αθόρυβες προεπιλογές του PDF συναντούν ανοχές προεκτύπωσης μετρημένες σε κλάσματα χιλιοστού, και μια βιβλιοθήκη είτε εφαρμόζει εκείνες τις προεπιλογές με τον ίδιο τρόπο παντού είτε σας παραδίδει δύο απαντήσεις σε μία ερώτηση. Το πλήρες API boxes, σύλληψης και Form XObject τεκμηριώνεται στη σελίδα προϊόντος PDFlibPas PDF Library for Delphi