Technical Article

3D Color LUTs σε PDF με Sampled Functions Τύπου 0

Οι συναρτήσεις PDF (PDF Functions) είναι μια από τις πιο ήσυχες γωνιές των προδιαγραφών. Οι περισσότεροι προγραμματιστές τις συναντούν μία φορά, ως αυτό που χρειάζεται μια αξονική σκίαση Τύπου 2 (Type 2 axial shading) για να ξεθωριάσει ανάμεσα σε δύο χρώματα, και δεν κοιτάζουν ποτέ ξανά. Αυτό είναι κρίμα, επειδή ο μηχανισμός των συναρτήσεων είναι ένας μικρός αξιολογητής γενικής χρήσης που η μορφή επαναχρησιμοποιεί για σκιάσεις, συναρτήσεις μεταφοράς (transfer functions), συναρτήσεις κουκκίδων ημιτόνου (halftone spot functions), αποχρώσεις διαχωρισμού (separation tints) και καμπύλες μεταφοράς απαλής μάσκας (soft-mask transfer curves). Από τους τέσσερις τύπους συναρτήσεων, ο Τύπος 0 είναι ο πιο ισχυρός και ο λιγότερο κατανοητός. Είναι μια δειγματοληπτική συνάρτηση (sampled function): ένα πολυδιάστατο πλέγμα τιμών εξόδου μεταξύ των οποίων παρεμβάλλει ο αναγνώστης. Επειδή το πλέγμα μπορεί να περιέχει οποιουσδήποτε αριθμούς τοποθετήσετε σε αυτό, μια συνάρτηση Τύπου 0 μπορεί να εκφράσει μια αυθαίρετη μη γραμμική χαρτογράφηση, η οποία είναι το ακριβές σχήμα ενός πίνακα αναζήτησης χρωμάτων (color lookup table).

Αυτό το άρθρο εξετάζει το λεξικό Τύπου 0 όπως το ορίζει το ISO 32000-1 στην §7.10.2, και στη συνέχεια δείχνει τις δύο περιπτώσεις που έχουν μεγαλύτερη σημασία σε μια ροή εργασίας εγγράφων: ένα LUT διόρθωσης χρώματος RGB-σε-RGB τριών εισόδων και έναν μετασχηματισμό απόχρωσης spot χρώματος μίας εισόδου. Ο ίδιος δημιουργός δειγματοληπτικών συναρτήσεων εξυπηρετεί και τα δύο, και η διαφορά μεταξύ τους είναι αποκλειστικά ζήτημα του πόσες εισόδους έχει το πλέγμα.

Μια δειγματοληπτική συνάρτηση είναι ένα πλέγμα που παρεμβάλλει ο αναγνώστης

Μια συνάρτηση Τύπου 0 αντιστοιχίζει ένα διάνυσμα εισόδου m σε ένα διάνυσμα εξόδου n αποθηκεύοντας δείγματα σε ένα κανονικό πλέγμα και παρεμβάλλοντας μεταξύ τους. ISO 32000-1 §7.10.2 παραθέτει τα κλειδιά που περιγράφουν αυτό το πλέγμα. Το /Domain περιέχει δύο αριθμούς ανά είσοδο, το χαμηλό και το υψηλό όριο κάθε άξονα εισόδου. Το /Range περιέχει δύο αριθμούς ανά στοιχείο εξόδου. Το /Size είναι ένας πίνακας από m ακέραιους αριθμούς που δίνει τον αριθμό των δειγμάτων κατά μήκος κάθε άξονα εισόδου, έτσι ώστε ένα πλέγμα που έχει δώδεκα δείγματα ανά πλευρά σε τρεις διαστάσεις να έχει /Size [12 12 12] και να αποθηκεύει 1.728 σημεία πλέγματος. Το /BitsPerSample ορίζει την ακρίβεια κάθε αποθηκευμένης τιμής. Το HotPDF δέχεται 1, 2, 4, 8, 12, 16, 24 και 32 bits, που ταιριάζουν με τις τιμές που επιτρέπει ο Πίνακας 38.

Η ροή δειγμάτων (sample stream) διαβάζεται με σταθερή σειρά. Η πρώτη διάσταση εισόδου μεταβάλλεται ταχύτερα, μετά η δεύτερη και ούτω καθεξής, και σε κάθε σημείο πλέγματος τα n στοιχεία εξόδου αποθηκεύονται με τη σειρά. Για έναν πίνακα RGB-σε-RGB, αυτό σημαίνει τρία byte ανά σημείο πλέγματος στα οκτώ bit, διατεταγμένα ως red-output, green-output, blue-output, σαρώνοντας πρώτα την κόκκινη είσοδο. Δύο ακόμη κλειδιά χαρτογραφούν τον συνεχή κόσμο στο ακέραιο πλέγμα. Το /Encode αντιστοιχίζει κάθε είσοδο από το διάστημά της /Domain στο εύρος δειγμάτων 0 έως Size[i] - 1, και το /Decode αντιστοιχίζει τους ακατέργαστους αποθηκευμένους ακέραιους πίσω στα διαστήματα /Range. Όταν τα αφήνετε στις προεπιλογές τους, μια είσοδος που εκτείνεται στο [0 1] προσγειώνεται καθαρά στο πλήρες πλέγμα και ένα αποθηκευμένο byte του 255 αποκωδικοποιείται στην κορυφή του εύρους εξόδου του, το οποίο είναι ακριβώς αυτό που θέλει ένα [0,1]-normalized color LUT.

Order 1 έναντι Order 3

Μεταξύ των σημείων του πλέγματος ο αναγνώστης πρέπει να κάνει παρεμβολή, και το /Order επιλέγει τον τρόπο. Το /Order 1 είναι πολυγραμμική παρεμβολή (multilinear interpolation): γραμμική κατά μήκος ενός άξονα, διγραμμική σε δύο, τριγραμμική σε τρεις. Είναι γρήγορη, είναι ακριβώς αυτό που κάνει το υλικό (hardware) στα περισσότερα προγράμματα προβολής, και για έναν ομαλό μετασχηματισμό χρώματος είναι συνήθως μη ανιχνεύσιμη από κάτι πιο περίπλοκο. Το /Order 3 ζητά παρεμβολή κυβικού spline (cubic-spline interpolation), η οποία προσαρμόζει μια πιο ομαλή καμπύλη μέσα από τα δείγματα με κόστος περισσότερη εργασία και ευρύτερη περιοχή υποστήριξης γύρω από κάθε αξιολογούμενο σημείο.

Η συμβιβαστική λύση είναι η πυκνότητα του πλέγματος έναντι της ομαλότητας της καμπύλης. Η κυβική σειρά αξίζει τα λεφτά της όταν το πλέγμα είναι αραιό και η χαρτογράφηση έχει ορατή καμπυλότητα, επειδή μια ευθεία γραμμή μεταξύ δύο απομακρυσμένων δειγμάτων μπορεί να ισιώσει μια καμπύλη τόνων με τρόπο που το μάτι εντοπίζει στις διαβαθμίσεις. Μόλις το πλέγμα γίνει πυκνό, τα τμήματα είναι αρκετά μικρά ώστε η γραμμική παρεμβολή να παρακολουθεί στενά την καμπύλη και η κυβική προσφέρει ελάχιστα. Ένας πρακτικός κανόνας είναι να καταφεύγετε στο /Order 3 μόνο με μικρά πλέγματα ή απότομους μετασχηματισμούς, και διαφορετικά να το αφήνετε στην προεπιλεγμένη γραμμική ρύθμιση. Σημειώστε ότι το /Order ισχύει μόνο για συναρτήσεις Τύπου 0, και το HotPDF απορρίπτει οποιαδήποτε άλλη τιμή εκτός από 1 ή 3.

Το 3D LUT: τρεις είσοδοι, τρεις έξοδοι

Μια διόρθωση χρώματος RGB-σε-RGB είναι η κλασική περίπτωση για ένα πλέγμα τριών εισόδων, το κλασικό 3D LUT που χρησιμοποιείται στη βαθμονόμηση χρώματος (color grading) και στην αντιστοίχιση συσκευών. Κάθε άξονας του κύβου είναι ένα κανάλι εισόδου, κάθε σημείο πλέγματος αποθηκεύει την διορθωμένη τριάδα RGB για αυτήν τη συντεταγμένη εισόδου, και ο αναγνώστης παρεμβάλλει τριγραμμικά τα δείγματα γωνίας γύρω από οποιοδήποτε εισερχόμενο χρώμα. Οι τρεις είσοδοι είναι αναπόφευκτες εδώ επειδή το διορθωμένο κόκκινο μπορεί να εξαρτάται από το εισερχόμενο πράσινο και μπλε, όχι μόνο από το εισερχόμενο κόκκινο. Μια καμπύλη ανά κανάλι δεν μπορεί να εκφράσει τη διασταύρωση καναλιών (channel crosstalk), αλλά ένας κύβος μπορεί.

Το HotPDF δημιουργεί τη ροή Τύπου 0 μέσω της RegisterSampledFunction, η οποία λαμβάνει απευθείας τα /Domain, /Range, /Size, /BitsPerSample και τα byte δειγμάτων και επιστρέφει το αντικείμενο συνάρτησης. Για έναν τυπικό κανονικοποιημένο κύβο, περνάτε όρια [0,1] και στους τρεις άξονες εισόδου και στις τρεις εξόδους, ένα μέγεθος N x N x N και τον επίπεδο πίνακα δειγμάτων. Ο δημιουργός επικυρώνει ότι το πλήθος των byte ταιριάζει με το πλέγμα: για βάθος ευθυγραμμισμένο με byte, αναμένει OutputCount x (BitsPerSample div 8) x το γινόμενο των μεγεθών, και εγείρει σφάλμα εάν ο πίνακας έχει λάθος μήκος, έτσι ώστε ένα εσφαλμένα υπολογισμένο βήμα (stride) να αποτυγχάνει ηχηρά κατά την καταχώριση αντί να αποδίδεται ως σκουπίδια αργότερα.

const
  N = 17;  // 17 x 17 x 17 cube, the common ICC LUT resolution
var
  LutFn: THPDFStreamObject;
  Samples: TBytes;
begin
  // Fill Samples with N*N*N grid points, 3 bytes each (R,G,B output),
  // red input varying fastest. Build the corrected triple for each
  // grid coordinate with your ICC-managed conversion, then store it.
  SetLength(Samples, N * N * N * 3);
  BuildCorrectedCube(Samples, N);   // your color-managed fill

  LutFn := Pdf.RegisterSampledFunction(
    [0,1, 0,1, 0,1],   // /Domain: three input axes on [0,1]
    [0,1, 0,1, 0,1],   // /Range:  three output channels on [0,1]
    [N, N, N],         // /Size:   the cube resolution per axis
    8,                 // /BitsPerSample
    Samples,
    1);                // /Order 1 = trilinear
end;

Η χρωματομετρική ορθότητα του κύβου βρίσκεται στον τρόπο που τον γεμίζετε, όχι στη συνάρτηση PDF. Η σωστή διαδρομή είναι να υπολογίσετε κάθε σημείο πλέγματος μέσω μιας μετατροπής διαχειριζόμενης από ICC, της ίδιας μηχανής που οδηγεί ένα soft-proof, ώστε οι αριθμοί στο πλέγμα να σημαίνουν κάτι έναντι ενός καθορισμένου προφίλ πηγής και προορισμού. Καταχωρίστε τα προφίλ που οριοθετούν τη μετατροπή με την RegisterICCProfile, η οποία καταγράφει έναν χρωματικό χώρο ICCBased (1, 3 ή 4 στοιχεία) και επιστρέφει ένα όνομα πόρου που μπορείτε να επισυνάψετε στο περιεχόμενο που τροφοδοτεί το LUT. Η συνάρτηση Τύπου 0 μεταφέρει τον πίνακα παρεμβολής. Το προφίλ ICC μεταφέρει τη σημασία των τελικών σημείων.

Η περίπτωση 1D: ένας μετασχηματισμός απόχρωσης spot χρώματος

Οι χρωματικοί χώροι διαχωρισμού (Separation color spaces) βασίζονται στον ίδιο μηχανισμό για μια εντελώς διαφορετική εργασία. Ένας χώρος Separation, που ορίζεται στο ISO 32000-1 §8.6.6.4, αντιπροσωπεύει ένα μεμονωμένο χρωστικό στοιχείο, ένα spot μελάνι όπως ένα Pantone ή ένα βερνίκι, συνδυάζοντας ένα όνομα με έναν μετασχηματισμό απόχρωσης (tint transform): μια συνάρτηση που αντιστοιχίζει τη μονοδιάστατη τιμή απόχρωσης, 0 για καθόλου μελάνι έως 1 για πλήρες μελάνι, σε έναν εναλλακτικό χρωματικό χώρο που μπορεί πραγματικά να αποδώσει η συσκευή, συνήθως CMYK. Αυτός ο μετασχηματισμός απόχρωσης είναι συχνά μια συνάρτηση Τύπου 0, και τώρα το πλέγμα έχει ακριβώς έναν άξονα εισόδου.

Αυτή είναι η καθαρή αντίθεση με το 3D LUT. Ένα spot μελάνι είναι ένας βαθμός ελευθερίας, επομένως ο μετασχηματισμός απόχρωσής του χρειάζεται μία είσοδο και το πλέγμα είναι μια γραμμή δειγμάτων, καθένα από τα οποία περιέχει την τιμή CMYK (ή άλλη εναλλακτική) σε αυτό το επίπεδο απόχρωσης. Ο κύβος RGB χρειάζεται τρεις εισόδους επειδή το πεδίο ορισμού του είναι τρισδιάστατο και τα κανάλια αλληλεπιδρούν. Ίδιος τύπος συνάρτησης, ίδιοι κανόνες παρεμβολής, διαφορετική διάσταση. Η προδιαγραφή επαναχρησιμοποιεί έναν αξιολογητή και αφήνει το /Size να αποφασίσει αν περπατάτε σε μια γραμμή, ένα επίπεδο ή έναν κύβο. Το HotPDF τυλίγει ολόκληρο το διαχωρισμό στη RegisterSeparationLUT, η οποία δημιουργεί εσωτερικά τον μετασχηματισμό απόχρωσης Τύπου 0 μίας εισόδου από έναν επίπεδο πίνακα byte και επιστρέφει το όνομα πόρου του χρωματικού χώρου.

var
  SpotCS: AnsiString;
begin
  // Four CMYK output bytes per tint grid point, tint domain [0..1].
  // Here 0% ink -> all zero, 100% ink -> a rich spot build,
  // with two interior steps; the tint transform interpolates between.
  SpotCS := Pdf.RegisterSeparationLUT(
    'PANTONE 286 C',         // colorant name
    'DeviceCMYK',            // alternate color space
    [  0,   0,   0,   0,     // tint 0.00 -> 0,0,0,0
      90,  60,   0,   0,     // tint 0.33
     100,  80,   0,  10,     // tint 0.66
     100,  72,   0,  18]);   // tint 1.00 -> full ink build
  // Use SpotCS with SetFillColorSpace / SetFillColor on a page.
end;

Το πλήθος των δειγμάτων πρέπει να είναι ένας ακέραιος αριθμός σημείων πλέγματος: ένα θετικό πολλαπλάσιο του πλήθους των στοιχείων του εναλλακτικού χώρου, και τουλάχιστον δύο σημεία ώστε να υπάρχει ένα τμήμα για παρεμβολή. Περάστε τρία byte ανά σημείο έναντι μιας εναλλακτικής CMYK και η κλήση την απορρίπτει, την ίδια αμυντική επικύρωση που εφαρμόζει ο τρισδιάστατος δημιουργός, κάτι που είναι αυτό που θέλετε από μια συνάρτηση που διαφορετικά θα αποτύγχανε σιωπηλά κατά την εκτύπωση.

Πού εμφανίζεται ξανά ο ίδιος μηχανισμός

Μόλις δείτε τον Τύπο 0 ως έναν γενικό πίνακα παρεμβολής, δύο ακόμα χαρακτηριστικά ελέγχου συσκευής παύουν να μοιάζουν με ειδικές περιπτώσεις. Μια συνάρτηση μεταφοράς (transfer function) προσαρμόζει τις τιμές των στοιχείων στο δρόμο τους προς τη συσκευή εξόδου, και είναι απλώς μια συνάρτηση ανά κανάλι. Το HotPDF την καταχωρίζει ως ExtGState μέσω της RegisterTransferFunctionState, η οποία δέχεται είτε μία συνδυασμένη συνάρτηση είτε έναν πίνακα συναρτήσεων ανά κανάλι. Επειδή αυτές οι συναρτήσεις είναι κοινά αντικείμενα συναρτήσεων, μπορείτε να της παραδώσετε το ίδιο το THPDFStreamObject που επιστρέφει η RegisterSampledFunction και να οδηγήσετε μια καμπύλη μεταφοράς από έναν δειγματοληπτικό πίνακα αντί για έναν τύπο.

var
  ToneFn: THPDFStreamObject;
  GsName: AnsiString;
begin
  // A single-input, single-output sampled tone curve on [0,1].
  ToneFn := Pdf.RegisterSampledFunction(
    [0,1], [0,1], [256], 8, ToneCurveBytes, 1);

  // Apply it to all channels as a combined /TR2 transfer function.
  GsName := Pdf.RegisterTransferFunctionState(ToneFn, []);
  // Select GsName on the page before drawing the affected content.
end;

Η δημιουργία μαύρου (black generation) και η αφαίρεση υπο-χρώματος (undercolor removal) ανήκουν στην ίδια οικογένεια. Όταν μια συσκευή μετατρέπει RGB σε CMYK, αποφασίζει πόσο από το γκρι στοιχείο θα μεταφέρει ως μαύρο μελάνι, και η προδιαγραφή εκφράζει αυτήν την απόφαση ως συνάρτηση, τις καταχωρίσεις /BG2 και /UCR2 ενός λεξικού κατάστασης γραφικών (graphics-state dictionary), καθεμία από τις οποίες είναι μια καμπύλη μίας εισόδου από το υπολογισμένο γκρι σε μια ποσότητα μαύρου. Αυτές είναι επίσης συναρτήσεις Τύπου 0 όταν θέλετε μια μετρημένη καμπύλη αντί για μια αναλυτική, κατασκευασμένες με τον ίδιο τρόπο μέσω της RegisterSampledFunction και τοποθετημένες στην κατάσταση γραφικών. Το μάθημα που αξίζει να κρατήσετε είναι ότι η συνάρτηση PDF δεν είναι ποτέ το μέρος όπου συμβαίνει η διαχείριση χρώματος. Είναι ο πίνακας αναζήτησης που μεταφέρει μια απόφαση που λάβατε με μια πραγματική μηχανή χρώματος, και ο Τύπος 0 είναι ο μόνος τύπος συνάρτησης αρκετά ευέλικτος ώστε να μεταφέρει οποιαδήποτε απόφαση.

Για την ευρύτερη εικόνα του πώς εκπέμπονται οι γραμματοσειρές, οι εικόνες και οι χρωματικοί πόροι σε ένα έτοιμο έγγραφο, δείτε τον οδηγό μας για την έξοδο αναφορών με γραμματοσειρές και εικόνες. Όταν η έξοδος πρέπει να επιβιώσει από έναν έλεγχο προετοιμασίας αρχειοθέτησης ή εκτύπωσης (preflight check), οι κανόνες χρωματικού χώρου και πρόθεσης εξόδου που καλύπτονται στον οδηγό επικύρωσης PDF/A, PDF/X και PDF/UA καθορίζουν ποιες από αυτές τις συναρτήσεις επιτρέπονται και πώς πρέπει να επισημαίνεται το χρώμα της συσκευής. Όλα αυτά διατίθενται στο HotPDF Component για Delphi και C++Builder, μαζί με τα API σκίασης, ICC και διαχωρισμού που βασίζονται στον ίδιο πυρήνα Τύπου 0.