Technical Article

3D szín-LUT-ok PDF-ben Type 0 mintavételezett függvényekkel

A PDF függvények (PDF Functions) a specifikáció csendesebb zugaiba tartoznak. A legtöbb fejlesztő egyszer találkozik velük, mint azzal a dologgal, amelyre a Type 2 tengelyirányú árnyékolásnak szüksége van két szín közötti átmenethez, és többet nem is néz feléjük. Ez kár, mert a függvénymechanizmus egy kis, általános célú kiértékelő, amelyet a formátum újrahasznál árnyékolásokhoz, transzferfüggvényekhez, autotípiai pontfunkciókhoz (halftone spot functions), direkt színes árnyalatokhoz (separation tints) és soft-mask átviteli görbékhez. A négy függvénytípus közül a Type 0 a legerősebb és a legkevésbé megértett. Ez egy mintavételezett függvény (sampled function): kimeneti értékek többdimenziós rácsa, amelynek pontjai között az olvasó interpolál. Mivel a rács bármilyen beírt számot tartalmazhat, a Type 0 függvény tetszőleges nemlineáris leképezést képes kifejezni, ami pontosan a színkereső táblázat (color lookup table) formája.

Ez a cikk végigvezeti a Type 0 szótáron úgy, hogyan azt az ISO 32000-1 a 7.10.2. szakaszban meghatározza, majd bemutatja azt a két esetet, amely a leginkább számít a dokumentum-munkafolyamatban: a három bemenetű RGB-RGB színkorrekciós LUT-ot, és az egy bemenetű direkt szín árnyalat-transzformációt. Ugyanaz a mintavételezett függvény-építő szolgálja ki mindkettőt, és a különbség közöttük teljesen abban rejlik, hogy hány bemenettel rendelkezik a rács.

A mintavételezett függvény egy rács, amelyet az olvasó interpolál

A mintavételezett függvény egy m-bemenetű vektort képez le egy n-kimenetű vektorra úgy, hogy mintákat tárol egy szabályos rácson, és interpolál közöttük. Az ISO 32000-1 7.10.2. szakasza felsorolja azokat a kulcsokat, amelyek leírják ezt a rácsot. A /Domain két számot tartalmaz bemenetenként, a bemeneti tengely alsó és felső határát. A /Range két számot tartalmaz kimeneti komponensenként. A /Size m darab egész szám tömbje, amely megadja a minták számát az egyes bemeneti tengelyek mentén, így egy három dimenzióban oldalanként tizenkét mintát tartalmazó rács /Size [12 12 12] méretű, és 1728 rácspontot tárol. A /BitsPerSample beállítja az egyes tárolt értékek pontosságát; a HotPDF az 1, 2, 4, 8, 12, 16, 24 és 32 bites értékeket fogadja el, a 38. táblázat által engedélyezett értékeknek megfelelően.

A minta-adatfolyam olvasása rögzített sorrendben történik. Az első bemeneti dimenzió változik a leggyorsabban, majd a második, és így tovább, és minden rácspontnál az n kimeneti komponens sorban van tárolva. Egy RGB-RGB táblázatnál ez rácspontonként három bájt nyolc biten, vörös-kimenet, zöld-kimenet, kék-kimenet elrendezésben, először a vörös bemeneten végighaladva. Két további kulcs képezi le a folytonos világot az egész számok rácsára. Az /Encode leképezi a bemeneteket a /Domain intervallumukról a 0 és Size[i] - 1 közötti mintaindex-tartományra, a /Decode pedig leképezi a nyers tárolt egész számokat a /Range intervallumokra. Ha ezeket az alapértelmezetten hagyja, a [0 1] tartományt átfogó bemenet tisztán illeszkedik a teljes rácsra, a 255 értékű tárolt bájt pedig a kimeneti tartománya tetejére dekódolódik, ami pontosan megfelel egy [0,1] tartományra normalizált szín-LUT igényeinek.

Order 1 és Order 3 összevetése

A rácspontok között az olvasónak interpolálnia kell, és a /Order határozza meg, hogyan. A /Order 1 multilineáris interpolációt jelent: lineáris egy tengely mentén, bilineáris kettőn keresztül, trilineáris hármon keresztül. Gyors, pontosan ez az, amit a legtöbb megjelenítő hardvere csinál, és egy sima színtranszformáció esetén általában megkülönböztethetetlen bármilyen bonyolultabb megoldástól. A /Order 3 köbös spline (cubic-spline) interpolációt kér, amely simább görbét illeszt a mintákra több munka és az értékelt pontok körüli szélesebb tartomány árán.

A kompromisszum a rács sűrűsége és a görbe simasága között van. A köbös sorrend meghálálja magát, ha a rács ritka és a leképezés látható görbülettel rendelkezik, mert a két távoli minta közötti egyenes vonal úgy lapíthatja el a tónusgörbét, hogy a szem észreveszi a színátmeneteken. Amint a rács sűrű, a szegmensek elég rövidek ahhoz, hogy a lineáris interpoláció szorosan kövesse a görbét, és a köbös kevés előnyt nyújt. Praktikus szabály, hogy a /Order 3 beállításhoz csak kis rácsok vagy meredek transzformációk esetén nyúljunk, egyébként hagyjuk meg a lineáris alapértelmezést. Megjegyzendő, hogy az /Order csak a Type 0 funkciókra vonatkozik, és a HotPDF elutasít minden 1-től vagy 3-tól eltérő értéket.

A 3D LUT: három bemenet, három kimenet

Az RGB-RGB színkorrekció a tankönyvi példa a három bemenetű rácsra, a klasszikus 3D LUT-ra, amelyet a színosztályozásnál (color grading) és eszközillesztésnél használnak. A kocka minden tengelye egy-egy bemeneti csatorna, minden rácspont a korrigált RGB hármast tárolja az adott bemeneti koordinátához, az olvasó pedig trilineárisan interpolálja a sarokmintákat a bejövő szín körül. A három bemenet itt elkerülhetetlen, mivel a korrigált vörös függhet a bemeneti zöld és kék színtől is, nem csak a bemeneti vöröstől; a csatornánkénti görbe nem képes kifejezni a csatornák közötti áthallást (crosstalk), de a kocka igen.

HotPDF builds the Type 0 stream through RegisterSampledFunction, which takes the /Domain, /Range, /Size, /BitsPerSample, and sample bytes directly and returns the function object. For a standard normalized cube you pass [0,1] bounds on all three input axes and all three outputs, an N x N x N size, and the flattened sample table. The builder validates that the byte count matches the grid: for a byte-aligned depth it expects OutputCount x (BitsPerSample div 8) x the product of the sizes, and raises if the array is the wrong length, so a miscomputed stride fails loudly at registration rather than rendering as garbage later.

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;

A kocka kolorimetriai helyessége abban rejlik, hogyan tölti fel azt, nem pedig a PDF függvényben. A helyes út az, ha minden rácspontot egy ICC-alapú konverzión keresztül számít ki – ugyanazon a motoron, amely a soft-proof megjelenítést is vezérli –, így a rácsban szereplő számok jelentenek valamit a meghatározott forrás- és célprofilhoz képest. Regisztrálja a konverziót határoló profilokat a RegisterICCProfile segítségével, amely rögzít egy ICCBased színteret (1, 3 vagy 4 komponens), és visszaad egy erőforrásnevet, amelyet hozzákapcsolhat a LUT által táplált tartalomhoz. A Type 0 függvény hordozza az interpolációs táblázatot; az ICC profil hordozza a végpontok jelentését.

Az 1D eset: direkt szín árnyalat-transzformáció

A Separation (színkivonati) színterek ugyanerre a mechanizmusra támaszkodnak egy teljesen más feladatnál. Az ISO 32000-1 8.6.6.4. szakaszában meghatározott Separation színtér egyetlen színezéket, például egy Pantone direkt színt (spot ink) vagy egy lakkot képvisel azáltal, hogy párosít egy nevet egy árnyalati transzformációval (tint transform): egy függvénnyel, amely leképezi az egydimenziós árnyalati értéket (0 jelenti a festék hiányát, 1 a teljes festéket) egy alternatív színtérre, amelyet az eszköz ténylegesen meg tud jeleníteni, általában CMYK-ra. Ez az árnyalati transzformáció gyakran egy Type 0 függvény, és most a rács pontosan egy bemeneti tengellyel rendelkezik.

Ez a tiszta különbség a 3D LUT-hoz kápest. A direkt szín egyetlen szabadsági fokkal rendelkezik, így az árnyalati transzformációjához egyetlen bemenet szükséges, a rács pedig minták egy vonala, amelyek mindegyike tartalmazza a CMYK (vagy más alternatív) értéket az adott árnyalati szinten. Az RGB kockának három bemenetre van szüksége, mivel a tartománya háromdimenziós, és a csatornák kölcsönhatásba lépnek egymással. Ugyanaz a függvénytípus, ugyanazok az interpolációs szabályok, eltérő dimenziószám; a specifikáció újrahasznál egy értékelőt, és hagyja, hogy a /Size döntse el, hogy egy vonalon, egy síkon vagy egy kockán haladunk-e. A HotPDF a teljes színkivonatot a RegisterSeparationLUT függvénybe csomagolja, amely belsőleg felépíti az egybemenetű Type 0 árnyalati transzformációt egy lapos bájt-tömbből, és visszaadja a színtér erőforrás nevét.

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;

A minták számának egész számú rácspontnak kell lennie: a választott alternatív színtér komponensei számának pozitív többszörösének, és legalább két pontnak, hogy legyen interpolálható szegmens. Ha pontonként három bájtot ad át egy CMYK alternatívával szemben, a hívás elutasítja azt – ugyanaz a védekező ellenőrzés, amelyet a 3D építő is alkalmaz, és pontosan ezt szeretné egy olyan függvénynél, amely egyébként csendben megbukna a nyomtatás során.

Ahol ugyanez a mechanizmus újra megjelenik

Ha a Type 0-ra úgy tekintünk, mint egy általános interpolációs táblázatra, két másik eszközvezérlő funkció sem tűnik többé speciális esetnek. A transzferfüggvény (transfer function) beállítja a komponensértékeket a kimeneti eszköz felé vezető úton, és ez egyszerűen csatornánként egy függvény; a HotPDF ezt ExtGState-ként regisztrálja a RegisterTransferFunctionState segítségével, amely elfogad egy kombinált függvényt vagy csatornánkénti függvények tömbjét. Mivel ezek a funkciók közönséges függvényobjektumok, átadhatja nekik pontosan azt a THPDFStreamObject-et, amelyet a RegisterSampledFunction ad vissza, és egy mintavételezett táblázatkból vezérelhet egy transzfergörbét képlet helyett.

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;

A feketegenerálás (black generation) és a szín alatti szín eltávolítása (undercolor removal) ugyanabba a családba tartozik. Amikor egy eszköz az RGB-t CMYK-ra konvertálja, eldönti, hogy a szürke komponens mekkora részét vigye át fekete festékként, és a specifikáció ezt a döntést függvényként fejezi ki – egy grafikai állapot szótár /BG2 és /UCR2 bejegyzéseiként –, amelyek mindegyike egy egybemenetű görbe a számított szürkeségből a fekete mennyiségébe. Ezek szintén Type 0 függvények, ha mért görbét szeretne analitikus helyett, amelyet ugyanúgy a RegisterSampledFunction segítségével építhet fel és helyezhet el a grafikai állapotban. A megjegyzendő tanulság az, hogy a PDF függvény soha nem az a hely, ahol a színkezelés történik; ez a keresőtáblázat, amely hordozza az Ön által egy valódi színmotorral meghozott döntést, és a Type 0 az az egyetlen függvénytípus, amely elég rugalmas ahhoz, hogy bármilyen döntést hordozzon.

Arról a tágabb képről, hogy a betűtípusok, képek és színerőforrások hogyan kerülnek kibocsátásra a kész dokumentumban, lásd a betűtípusokkal és képekkel rendelkező jelentéskimenetről szóló útmutatónkat. Ha a kimenetnek túl kell élnie egy archív vagy nyomtatási ellenőrzést, a PDF/A, PDF/X és PDF/UA hitelesítési útmutatóban ismertetett színtér- és kimeneti szándék (output-intent) szabályok határozzák meg, hogy ezen funkciók közül melyek engedélyezettek, és hogyan kell megjelölni az eszköz színét. Mindez a Delphi és C++Builder platformokhoz készült HotPDF Component csomagban érhető el, a shader, ICC és színkivonási API-kkal együtt, amelyek ugyanerre a Type 0 magra épülnek.