Funkce PDF jsou jedním z tišších koutů specifikace. Většina vývojářů se s nimi setká pouze jednou, jako s prvkem, který axiální stínování typu 2 potřebuje k přechodu mezi dvěma barvami, a už se k nim nevrátí. To je škoda, protože mechanismus funkcí je malý univerzální vyhodnocovač, který formát opakovaně používá pro stínování, přenosové funkce, půltónové bodové funkce, tónování separací a přenosové křivky měkkých masek. Ze čtyř typů funkcí je typ 0 nejvýkonnější a nejméně chápaný. Jedná se o vzorkovanou funkci (sampled function): vícerozměrnou mřížku výstupních hodnot, mezi kterými čtečka interpoluje. Protože mřížka může obsahovat jakákoli čísla, která do ní vložíte, funkce typu 0 dokáže vyjádřit libovolné nelineární mapování, což je přesný tvar barevné vyhledávací tabulky (color lookup table).
Tento článek provází adresářem typu 0, jak jej definuje ISO 32000-1 v §7.10.2, a poté ukazuje dva případy, na kterých v dokumentové pipeline záleží nejvíce: třívstupovou tabulku LUT pro korekci barev z RGB do RGB a jednovstupovou transformaci odstínu přímé barvy. Oběma slouží stejný tvůrce vzorkovaných funkcí a rozdíl mezi nimi je čistě otázkou toho, kolik vstupů mřížka má.
Vzorkovaná funkce je mřížka, kterou čtečka interpoluje
Funkce typu 0 mapuje m-vstupový vektor na n-výstupový vektor ukládáním vzorků na pravidelné mřížce a interpolací mezi nimi. ISO 32000-1 §7.10.2 uvádí klíče, které tuto mřížku popisují. /Domain obsahuje dvě čísla na vstup, dolní a horní mez každé vstupní osy. /Range obsahuje dvě čísla na výstupní komponentu. /Size je pole m celých čísel udávající počet vzorků podél každé vstupní osy, takže mřížka, která má v trojrozměrném prostoru dvanáct vzorků na každé straně, má /Size [12 12 12] a ukládá 1 728 bodů mřížky. /BitsPerSample nastavuje přesnost každé uložené hodnoty; HotPDF přijímá 1, 2, 4, 8, 12, 16, 24 a 32 bitů, což odpovídá hodnotám povoleným v tabulce 38.
Proud vzorků je čten v pevném pořadí. První vstupní rozměr se mění nejrychleji, poté druhý atd., a v každém bodě mřížky je uloženo n výstupních komponent v daném pořadí. Pro tabulku z RGB do RGB jsou to tři bajty na bod mřížky při osmi bitech, uspořádané jako červený výstup, zelený výstup, modrý výstup, přičemž se nejprve prochází červený vstup. Dva další klíče mapují spojitý svět na celočíselnou mřížku. /Encode mapuje každý vstup z jeho intervalu /Domain na rozsah indexů vzorků 0 až Size[i] - 1 a /Decode mapuje nezpracovaná uložená celá čísla zpět na intervaly /Range. Když je ponecháte na výchozích hodnotách, vstup pokrývající [0 1] dopadne přesně na celou mřížku a uložený bajt s hodnotou 255 se dekóduje na vrchol svého výstupního rozsahu, což je přesně to, co tabulka LUT s normalizací [0,1] vyžaduje.
Řád 1 versus Řád 3
Mezi body mřížky musí čtečka interpolovat a /Order určuje jak. /Order 1 je multilineární interpolace: lineární podél jedné osy, bilineární ve dvou, trilineární ve třech rozměrech. Je rychlá, je to přesně to, co dělá hardware ve většině prohlížečů, a pro hladkou transformaci barev je obvykle nerozeznatelná od složitějších metod. /Order 3 vyžaduje kubickou spline interpolaci, která prokládá vzorky hladší křivkou za cenu většího množství práce a širší podpůrné oblasti kolem každého vyhodnocovaného bodu.
Kompromisem je hustota mřížky vůči hladkosti křivky. Kubický řád se vyplatí, když je mřížka řídká a mapování vykazuje viditelné zakřivení, protože přímka mezi dvěma vzdálenými vzorky může zploštit tónovou křivku způsobem, který oko u přechodů zaznamená. Jakmile je mřížka hustá, segmenty jsou dostatečně krátké na to, aby lineární interpolace sledovala křivku těsně, a kubická přináší jen malý užitek. Praktickým pravidlem je sahat po /Order 3 pouze u malých mřížek nebo strmých transformací, a jinak ponechat výchozí lineární nastavení. Upozorňujeme, že /Order se vztahuje pouze na funkce typu 0 a HotPDF odmítá jakoukoli jinou hodnotu než 1 nebo 3.
3D LUT: tři vstupy, tři výstupy
Korekce barev z RGB do RGB je učebnicovým příkladem třívstupové mřížky, klasické 3D tabulky LUT používané při barevných úpravách a slaďování zařízení. Każdá osa krychle je jedním vstupním kanálem, každý bod mřížky ukládá opravenou trojici RGB pro danou vstupní souřadnici a čtečka trilineárně interpoluje rohové vzorky kolem jakékoli přicházející barvy. Tři vstupy jsou zde nezbytné, protože opravená červená může záviset na vstupní zelené a modré, nikoli pouze na vstupní červené; křivka pro jednotlivé kanály nedokáže vyjádřit přeslech mezi kanály (channel crosstalk), ale krychle ano.
HotPDF sestavuje proud typu 0 prostřednictvím RegisterSampledFunction, které přebírá přímo /Domain, /Range, /Size, /BitsPerSample a bajty vzorků a vrací objekt funkce. Pro standardní normalizovanou krychli předáte meze [0,1] na všech třech vstupních osách i všech třech výstupech, velikost N x N x N a plochou tabulku vzorků. Tvůrce ověřuje, zda počet bajtů odpovídá mřížce: pro bajtově zarovnanou hloubku očekává součin OutputCount x (BitsPerSample div 8) x velikostí a vyvolá chybu, pokud má pole nesprávnou délku, takže nesprávně vypočítaný krok (stride) selže hlasitě již při registraci, namísto toho, aby se později zobrazil jako poškozená data.
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;
Kolorimetrická správnost krychle spočívá v tom, jak ji naplníte, nikoli ve funkci PDF. Správnou cestou je vypočítat každý bod mřížky prostřednictvím převodu řízeného profily ICC (stejný engine, který řídí soft-proof), aby čísla v mřížce měla význam vůči definovanému zdrojovému a cílovému profilu. Zaregistrujte profily, které omezují převod, pomocí RegisterICCProfile, což zaznamená barevný prostor ICCBased (1, 3 nebo 4 komponenty) a vrátí název prostředku, který můžete připojit k obsahu, jejž tabulka LUT napájí. Funkce typu 0 nese interpolační tabulku; profil ICC nese význam koncových bodů.
1D případ: transformace odstínu přímé barvy
Separační barevné prostory staví na stejném mechanismu pro zcela jinou úlohu. Separační prostor (Separation space), definovaný v ISO 32000-1 §8.6.6.4, představuje jedno barvivo (přímý inkoust, jako je Pantone nebo lak) spojením názvu s transformací odstínu (tint transform): funkcí, která mapuje jednorozměrnou hodnotu odstínu, od 0 pro žádný inkoust po 1 pro plný inkoust, na alternativní barevný prostor, který zařízení dokáže skutečně vykreslit, obvykle CMYK. Tato transformace odstínu je často funkcí typu 0 a mřížka má nyní přesně jednu vstupní osu.
To je jasný kontrast s 3D LUT. Přímý inkoust má jeden stupeň volnosti, takže jeho transformace odstínu potřebuje jeden vstup a mřížkou je řada vzorků, z nichž každý obsahuje hodnotu CMYK (nebo jinou alternativní) na dané úrovni odstínu. Krychle RGB potřebuje tři vstupy, protože její doména je trojrozměrná a kanály se ovlivňují. Stejný typ funkce, stejná pravidla interpolace, jiná dimenzionalita; specifikace opakovaně používá jeden vyhodnocovač a nechává /Size rozhodnout, zda procházíte čáru, rovinu nebo krychli. HotPDF balí celou separaci do RegisterSeparationLUT, které interně sestaví jednovstupovou transformaci odstínu typu 0 z plochého pole bajtů a vrátí název prostředku barevného prostoru.
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;
Počet vzorků musí být celým počtem bodů mřížky: kladným násobkem počtu komponent alternativního prostoru a alespoň dvěma body, aby existoval segment k interpolaci. Pokud předáte tři bajty na bod oproti alternativě CMYK, volání to odmítne. Jedná se o stejnou obrannou validaci, jakou používá 3D tvůrce, což je přesně to, co chcete od funkce, která by jinak při tisku tiše selhala.
Kde se stejný mechanismus objevuje znovu
Jakmile pochopíte typ 0 jako obecnou interpolační tabulku, přestanou další dvě funkce řízení zařízení vypadat jako speciální případy. Přenosová funkce (transfer function) upravuje hodnoty komponent na jejich cestě k výstupnímu zařízení a jde o pouhou funkci na kanál; HotPDF ji registruje jako ExtGState prostřednictvím RegisterTransferFunctionState, které přijímá buď jednu kombinovanou funkci, nebo pole funkcí pro jednotlivé kanály. Vzhledem k tomu, že tyto funkce jsou běžnými objekty funkcí, můžete jim předat přesně ten THPDFStreamObject, který vrací RegisterSampledFunction, a řídit přenosovou křivku ze vzorkované tabulky namísto vzorce.
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;
Generování černé (black generation) a odstranění podkladové barvy (undercolor removal) spadají do stejné rodiny. Když zařízení převádí RGB na CMYK, rozhoduje o tom, jak velkou část šedé složky přenese jako černý inkoust, a specifikace toto rozhodnutí vyjadřuje jako funkci, konkrétně položky /BG2 a /UCR2 adresáře grafického stavu, z nichž každá je jednovstupovou křivkou od vypočtené šedi k množství černé. To jsou také funkce typu 0, pokud chcete spíše naměřenou křivku než analytickou, sestavené stejným způsobem přes RegisterSampledFunction a umístěné do grafického stavu. Důležitým ponaučením je, že funkce PDF nikdy není místem, kde dochází ke správě barev; je to vyhledávací tabulka, která nese rozhodnutí učiněné skutečným barevným enginem, a typ 0 je jediným typem funkce, který je dostatečně flexibilní, aby nesl jakékoli rozhodnutí.
Pro širší přehled o tom, jak jsou písma, obrázky a barevné prostředky emitovány do výsledného dokumentu, viz náš průvodce výstupem sestav s písmy a obrázky. Pokud musí výstup projít archivační nebo tiskovou kontrolou preflight, pravidla pro barevné prostory a záměry výstupu (output intent) popsaná v příručce pro validaci PDF/A, PDF/X a PDF/UA určují, které z těchto funkcí jsou povoleny a jak musí být barvy zařízení označeny. To vše je dodáváno v produktu HotPDF Component pro Delphi and C++Builder spolu s rozhraními API pro stínování, ICC a separace, která staví na stejném jádru typu 0.