Τεχνικό Άρθρο

Προεπιλογές TrimBox, BleedBox, CropBox στο PDFlibPas

Όταν μια σελίδα 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

BoxBoxType PDFlibPasΠροεπιλογή όταν λείπειΚληρονομείται από /Pages
MediaBox1Κανένα, η εγγραφή είναι υποχρεωτικήΝαι
CropBox2MediaBoxΝαι
BleedBox3CropBoxΌχι
TrimBox4CropBoxΌχι
ArtBox5CropBoxΌχι

Η αλυσίδα δύο βημάτων μετράει επειδή το CropBox μπορεί το ίδιο να κληρονομείται. Το δραστικό TrimBox μιας σελίδας που δεν έχει ούτε TrimBox ούτε δικό της CropBox είναι το CropBox του πλησιέστερου προγόνου που έχει ένα, και σε αποτυχία, το κληρονομημένο MediaBox. Η προδιαγραφή προσθέτει έναν ακόμα κανόνα που ξεχνιέται εύκολα: τα crop, bleed, trim και art boxes δεν πρέπει να εκτείνονται πέρα από το media box, και αν το κάνουν, ανάγονται δραστικά στην τομή τους με εκείνο. Το PDFlibPas αναφέρει κάθε box όπως είναι αποθηκευμένο στο αρχείο, οπότε ένας validator που χειρίζεται αναξιόπιστη είσοδο πρέπει να το περιορίζει μόνος του στο MediaBox

Αλυσίδα προεπιλογών page box PDFlibPas όπου το CropBox προεπιλέγεται στο MediaBox και το BleedBox, TrimBox και ArtBox προεπιλέγεται καθένα στο CropBox, σχεδιασμένη δίπλα σε εσωτερικό βιβλίου με MediaBox 450 επί 666 points και CropBox 432 επί 648 points που γίνεται το δραστικό trim όταν δεν υπάρχει TrimBox
Τίποτα εκτός από το CropBox δεν προεπιλέγεται απευθείας στο MediaBox, οπότε μια σελίδα με μόνο MediaBox έχει πέντε πανομοιότυπα boxes

Ποιες ιδιότητες σελίδας μπορεί να κληροδοτήσει ένας κόμβος /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 που κληρονομεί τα πάντα βλέπει την τιμή του γονέα. Σε προεκτυπωτική ροή εκείνη η αμφισημία καταλήγει στο φύλλο εκτύπωσης

Κληρονομιά page tree PDFlibPas όπου μόνο Resources, MediaBox, CropBox και Rotate κληροδοτούνται από κόμβο Pages, ώστε ένα TrimBox παρκαρισμένο στη ρίζα είναι μη πρότυπο κλειδί που αγνοούν οι συμμορφούμενοι readers· πριν το v3.539.44 δύο ανεξάρτητες διαδρομές κώδικα το κληρονομούσαν και ανέφεραν διαφορετικά μεγέθη trim για το ίδιο έγγραφο
Το αρχείο σημαίνει δύο πράγματα ανάλογα με το ποιος το διαβάζει, και σε προεκτυπωτική ροή εκείνη η αμφισημία προσγειώνεται στο φύλλο εκτύπωσης

Οι ροές 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 PDFlibPas μηδέν, ένα και δύο με άμεσους και indirect πίνακες να μετρούν αμφότεροι ως κληρονομημένοι από το v3.539.44, δίπλα στα options μηδέν έως τέσσερα του CapturePageEx όπου BleedBox, TrimBox και ArtBox υποχωρούν στο CropBox αντί για το MediaBox από το v3.539.42
Δύο σημεία εισόδου υλοποίησης για έναν κανόνα προδιαγραφής διορθώνονται μαζί και τεστάρονται ως μήτρα 18 σεναρίων, με query και σύλληψη να συμφωνούν σε κάθε αρχείο

Το 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 Bottom
  • HasPageBox(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