PDF-funktioner er et af de mere stille hjørner af specifikationen. De fleste udviklere møder dem kun én gang, som det, en Type 2 aksial skyggelægning har brug for for at tone ud mellem to farver, og ser aldrig på dem igen. Det er en skam, fordi funktionsmaskineriet er en lille generel evaluator, som formatet genbruger til skyggelægninger, overførselsfunktioner (transfer functions), halvtonepunktfunktioner, separationsfarvetoner og soft-mask overførselskurver. Ud af de fire funktionstyper er Type 0 den mest kraftfulde og den mindst forståede. Det er en samplet funktion: et flerdimensionalt gitter af outputværdier, som læseren interpolerer imellem. Fordi gitteret kan indeholde alle de tal, du lægger i det, kan en Type 0-funktion udtrykke en vilkårlig ikke-lineær afbildning, hvilket er den præcise form af en farveopslagstabel (color lookup table).
Denne artikel gennemgår Type 0-ordbogen, som ISO 32000-1 definerer den i §7.10.2, og viser derefter de to tilfælde, der betyder mest i en dokumentpipeline: en tre-input RGB-til-RGB farvekorrektions-LUT og en enkelt-input spotfarve-toningstransformation. Den samme generator til samplede funktioner betjener begge dele, og forskellen på dem er udelukkende et spørgsmål om, hvor mange indgange gitteret har.
En samplet funktion is et gitter, som læseren interpolerer
En Type 0-funktion afbilder en m-inputvektor til en n-outputvektor ved at gemme samplingspunkter (samples) på et regelmæssigt gitter og interpolere imellem dem. ISO 32000-1 §7.10.2 lister de nøgler, der beskriver dette gitter. /Domain indeholder to tal pr. input, den nedre og øvre grænse for hver inputakse. /Range indeholder to tal pr. outputkomponent. /Size er et array af m heltal, der angiver antallet af samplingspunkter langs hver inputakse, så et gitter, der er tolv punkter på hver led i tre dimensioner, har /Size [12 12 12] og gemmer 1.728 gitterpunkter. /BitsPerSample indstiller præcisionen for hver gemt værdi; HotPDF accepterer 1, 2, 4, 8, 12, 16, 24 og 32 bit, hvilket svarer til de værdier, tabel 38 tillader.
Samplingsstrømmen læses i en fast rækkefølge. Den første inputdimension varierer hurtigst, derefter den anden og så fremdeles, og ved hvert gitterpunkt gemmes de n outputkomponenter i rækkefølge. For en RGB-til-RGB-tabel er det tre byte pr. gitterpunkt ved otte bit, udlagt som rød-output, grøn-output, blå-output, fejet hen over det røde input først. Yderligere to nøgler afbilder den kontinuerlige verden på det heltallige gitter. /Encode afbilder hvert input fra dets /Domain-interval to samplingsindeksintervallet 0 til Size[i] - 1, og /Decode afbilder de rå gemte heltal tilbage til /Range-intervallerne. Når du lader dem stå på deres standardværdier, et input, der spænder over [0 1], lander rent på det fulde gitter, og en gemt byte på 255 afkodes til toppen af dets outputinterval, hvilket er præcis, hvad en [0,1]-normaliseret farve-LUT forventer.
Orden 1 over for Orden 3
Mellem gitterpunkter skal læseren interpolere, og /Order vælger hvordan. /Order 1 er multilineær interpolation: lineær langs én akse, bilineær over to, trilineær over tre. Det er hurtigt, det er præcis det, hardwaren i de fleste fremvisere gør, og for en glat farvetransformation er det normalt umuligt at skelne fra noget mere avanceret. /Order 3 anmoder om kubisk spline-interpolation, som tilpasser en glattere kurve gennem punkterne på bekostning af mere arbejde og et bredere støtteområde omkring hvert evalueret punkt.
Afvejningen er gittertæthed over for kurveglathed. Kubisk orden gør gavn, når gitteret er groft, og afbildningen har en synlig krumning, fordi en ret linje mellem to fjerne samplingspunkter kan fladgøre en tonekurve på en måde, som øjet opfanger på farveovergange. Når først gitteret er tæt, er segmenterne korte nok til, at lineær interpolation følger kurven tæt, og kubisk giver kun en lille fordel. En praktisk regel er kun at gribe ud efter /Order 3 ved små gitre eller stejle transformationer, og ellers lade den stå på den lineære standardværdi. Bemærk, at /Order kun gælder for Type 0-funktioner, og HotPDF afviser enhver anden værdi end 1 eller 3.
The 3D LUT: tre indgange, tre udgange
En RGB-til-RGB-farvekorrektion er det klassiske eksempel på et gitter med tre indgange, den klassiske 3D LUT, der bruges til farvegraduering og enhedstilpasning. Hver akse i terningen er én inputkanal, hvert gitterpunkt gemmer den korrigerede RGB-triple for den pågældende inputkoordinat, og læseren interpolerer trilineært hjørnepunkterne omkring enhver indkommende farve. Tre indgange er uundgåelige her, fordi den korrigerede røde kan afhænge af input grøn og blå, ikke kun af input rød; en kurve pr. kanal kan ikke udtrykke krydstale mellem kanalerne, men en terning kan.
HotPDF opretter Type 0-strømmen via RegisterSampledFunction, som tager /Domain, /Range, /Size, /BitsPerSample og samplingsbytes direkte og returnerer funktionsobjektet. For en standard normaliseret terning angiver du [0,1]-grænser på alle tre inputakser og alle tre output, en N x N x N-størrelse og den flade samplingstabel. Generatoren validerer, at byte-antallet matcher gitteret: for en byte-justeret dybde forventer den OutputCount x (BitsPerSample div 8) x produktet af størrelserne og rejser en fejl, hvis arrayet har den forkerte længde, så en fejlberegnet stride fejler højlydt ved registreringen i stedet for at rendere som vrøvl senere.
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],
[0,1, 0,1, 0,1],
[N, N, N],
8,
Samples,
1);
end;
Den kolorimetriske korrekthed af terningen ligger i, hvordan du udfylder den, ikke i PDF-funktionen. Den korrekte vej er at beregne hvert gitterpunkt via en ICC-styret konvertering, den samme motor der driver en soft-proof, så tallene i gitteret betyder noget i forhold til en defineret kilde- og målprofil. Registrer de profiler, der afgrænser konverteringen, med RegisterICCProfile, som registrerer et ICCBased farverum (1, 3 eller 4 komponenter) og returnerer et ressourcenavn, du kan knytte til det indhold, som LUT'en føder. Type 0-funktionen bærer interpolationstabellen; ICC-profilen bærer betydningen af endepunkterne.
1D-tilfældet: en spotfarve-toningstransformation
Separationsfarverum læner sig op ad det samme maskineri til en helt anden opgave. Et separationsrum (Separation space), defineret i ISO 32000-1 §8.6.6.4, repræsenterer et enkelt farvestof, en spotfarve såsom en Pantone eller en lak, ved at parre et navn med en toningstransformation (tint transform): en funktion, der afbilder den endimensionelle toningsværdi, 0 for intet blæk til 1 for fuldt blæk, til et alternativt farverum, som enheden faktisk kan rendere, normalt CMYK. Den toningstransformation er ofte en Type 0-funktion, og her har gitteret nøjagtig én inputakse.
Dette er den klare kontrast til 3D LUT'en. En spotfarve er én frihedsgrad, så dens toningstransformation har brug for ét input, og gitteret er en linje af samplingspunkter, der hver især indeholder CMYK-værdien (eller en anden alternativ værdi) ved det pågældende toningsniveau. RGB-terningen har brug for tre input, fordi dens domæne er tredimensionalt, og kanalerne interagerer. Samme funktionstype, samme interpolationsregler, forskellig dimensionalitet; specifikationen genbruger én evaluator og lader /Size bestemme, om du går på en linje, en plan eller en terning. HotPDF indkapsler hele separationen i RegisterSeparationLUT, som internt bygger den Type 0-toningstransformation med ét input ud fra et fladt byte-array og returnerer farverummets ressourcenavn.
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',
'DeviceCMYK',
[ 0, 0, 0, 0,
90, 60, 0, 0,
100, 80, 0, 10,
100, 72, 0, 18]);
end;
Antallet af samplingspunkter skal være et helt antal gitterpunkter: et positivt multiplum af det alternative rums komponentantal, og mindst to punkter, så der er et segment at interpolere. Hvis du sender tre byte pr. punkt mod et CMYK-alternativ, afviser kaldet det. Det er den samme defensive validering, som 3D-generatoren anvender, hvilket er præcis, hvad du ønsker fra en funktion, der ellers ville fejle lydløst under udskrivning.
Hvor det samme maskineri dukker op igen
Når først du ser Type 0 som en generisk interpolationstabel, to yderligere enhedskontrolfunktioner holdt op med at ligne specialtilfælde. En overførselsfunktion (transfer function) justerer komponentværdier på deres vej til outputenheden, og det er blot en funktion pr. kanal; HotPDF registrerer den som en ExtGState via RegisterTransferFunctionState, som accepterer enten én kombineret funktion eller et array af funktioner pr. kanal. Fordi disse funktioner er almindelige funktionsobjekter, kan du give den netop det THPDFStreamObject, som RegisterSampledFunction returnerer, og drive en overførselskurve fra en samplet tabel i stedet for en formel.
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;
Sortgenerering (black generation) og underfarvefjernelse (undercolor removal) hører til i samme familie. Når en enhed konverterer RGB til CMYK, bestemmer den, hvor meget af gråkomponenten der skal bæres som sort blæk, og specifikationen udtrykker denne beslutning som en funktion, /BG2- og /UCR2-posterne i en grafikstatus-ordbog, hver især en kurve med enkelt input fra den beregnede grå til en sort mængde. Disse er også Type 0-funktioner, når du ønsker en målt kurve frem for en analytisk, bygget på samme måde via RegisterSampledFunction og placeret i grafikstatussen. Læren værd at huske er, at PDF-funktionen aldrig er der, hvor farvestyring finder sted; den er opslagstabellen, der bærer en beslutning, du har truffet med en rigtig farvemotor, og Type 0 is den eneste funktionstype, der er fleksibel nok til at bære en hvilken som helst beslutning.
For at få det bredere billede af, hvordan skrifttyper, billeder og farveressourcer udsendes i et færdigt dokument, se vores gennemgang af rapportoutput med skrifttyper og billeder. Når outputtet skal overleve et arkiv- eller print-preflight-tjek, bestemmer reglerne for farverum og output-hensigt (output intent), dækket i valideringsvejledningen til PDF/A, PDF/X og PDF/UA, hvilke af disse funktioner der er tilladt, og hvordan enhedsfarver skal tagges. Alt dette leveres i HotPDF Component til Delphi og C++Builder sammen med API'erne til skyggelægning, ICC og separation, der bygger på den samme Type 0-kerne.