PDF-Funktionen gehören zu den ruhigeren Ecken der Spezifikation. Die meisten Entwickler begegnen ihnen nur einmal – als das, was eine axiale Schattierung des Typs 2 benötigt, um zwischen zwei Farben überzugehen – und schauen nie wieder hin. Das ist schade, denn die Funktionsmaschinerie ist ein kleiner Allzweck-Evaluator, den das Format für Schattierungen, Transferfunktionen, Halbton-Rasterfunktionen, Schmuckfarben-Tönungen und Soft-Mask-Transferkurven wiederverwendet. Von den vier Funktionstypen ist Typ 0 der leistungsfähigste und am wenigsten verstandene. Es handelt sich um eine abgetastete Funktion (sampled function): ein mehrdimensionales Gitter von Ausgabewerten, zwischen denen der Reader interpoliert. Da das Gitter beliebige Zahlen aufnehmen kann, kann eine Typ-0-Funktion eine beliebige nichtlineare Zuordnung ausdrücken, was genau der Form einer Farbnachschlagetabelle (LUT) entspricht.
Dieser Artikel führt durch das Typ-0-Dictionary, wie es in ISO 32000-1 §7.10.2 definiert ist, und zeigt dann die beiden Fälle, die in einer Dokumenten-Pipeline am wichtigsten sind: eine RGB-zu-RGB-Farbkorrektur-LUT mit drei Eingängen und eine Schmuckfarben-Tönungskonvertierung mit einem Eingang. Derselbe Generator für abgetastete Funktionen bedient beide, und der Unterschied zwischen ihnen ist lediglich eine Frage der Anzahl der Eingänge des Gitters.
Eine abgetastete Funktion ist ein Gitter, das der Reader interpoliert
Eine Typ-0-Funktion bildet einen m-dimensionalen Eingangsvektor auf einen n-dimensionalen Ausgangsvektor ab, indem sie Abtastwerte (Samples) auf einem regelmäßigen Gitter speichert und zwischen ihnen interpoliert. ISO 32000-1 §7.10.2 listet die Schlüssel auf, die dieses Gitter beschreiben. /Domain enthält zwei Zahlen pro Eingang, die untere und obere Grenze jeder Eingangsachse. /Range enthält zwei Zahlen pro Ausgangskomponente. /Size ist ein Array von m Ganzzahlen, das die Anzahl der Samples entlang jeder Eingangsachse angibt. Ein Gitter mit zwölf Samples pro Seite in drei Dimensionen hat also /Size [12 12 12] und speichert 1.728 Gitterpunkte. /BitsPerSample legt die Genauigkeit jedes gespeicherten Wertes fest; HotPDF akzeptiert 1, 2, 4, 8, 12, 16, 24 und 32 Bit, was den in Tabelle 38 zulässigen Werten entspricht.
Der Sample-Datenstrom wird in einer festen Reihenfolge gelesen. Die erste Eingangsdimension variiert am schnellsten, dann die zweite und so weiter, und an jedem Gitterpunkt werden die n Ausgangskomponenten der Reihe nach gespeichert. Für eine RGB-zu-RGB-Tabelle sind das drei Byte pro Gitterpunkt bei acht Bit, angeordnet nach Rot-Ausgang, Grün-Ausgang, Blau-Ausgang, wobei zuerst der rote Eingang durchlaufen wird. Zwei weitere Schlüssel bilden die kontinuierliche Welt auf das Ganzzahlgitter ab. /Encode bildet jeden Eingang von seinem /Domain-Intervall auf den Sample-Indexbereich 0 bis Size[i] - 1 ab, und /Decode bildet die rohen gespeicherten Ganzzahlen zurück auf die /Range-Intervalle ab. Wenn Sie diese bei ihren Standardwerten belassen, ein Eingang, der sich über [0 1] erstreckt, landet sauber auf dem gesamten Gitter, und ein gespeichertes Byte von 255 wird als das Maximum seines Ausgangsbereichs dekodiert, was genau das ist, was eine [0,1]-normierte Farb-LUT benötigt.
Ordnung 1 versus Ordnung 3
Zwischen den Gitterpunkten muss der Reader interpolieren, und /Order wählt aus, wie. /Order 1 ist multilineare Interpolation: linear entlang einer Achse, bilinear über zwei, trilinear über drei. Sie ist schnell, entspricht genau dem, was die Hardware in den meisten Viewern tut, und ist bei einer glatten Farbumwandlung in der Regel nicht von komplexeren Methoden zu unterscheiden. /Order 3 fordert eine kubische Spline-Interpolation an, die eine glattere Kurve durch die Samples legt, allerdings auf Kosten von mehr Rechenaufwand und einem größeren Stützbereich um jeden ausgewerteten Punkt herum.
Der Kompromiss liegt zwischen Gitterdichte und Kurvenglätte. Die kubische Ordnung bewährt sich, wenn das Gitter grob ist und die Abbildung eine sichtbare Krümmung aufweist, da eine gerade Linie zwischen zwei weit entfernten Samples eine Tonwertkurve so abflachen kann, dass das Auge dies bei Verläufen wahrnimmt. Sobald das Gitter dicht ist, sind die Segmente kurz genug, dass die lineare Interpolation der Kurve eng folgt und die kubische kaum einen Mehrwert bietet. Eine praktische Regel lautet, /Order 3 nur bei kleinen Gittern oder steilen Transformationen zu verwenden und ansonsten bei der linearen Voreinstellung zu bleiben. Beachten Sie, dass /Order nur für Typ-0-Funktionen gilt und HotPDF jeden anderen Wert als 1 oder 3 ablehnt.
Die 3D-LUT: drei Eingänge, drei Ausgänge
Eine RGB-zu-RGB-Farbkorrektur ist der klassische Fall für ein Gitter mit drei Eingängen – die klassische 3D-LUT, die bei der Farbabstimmung und Geräteanpassung verwendet wird. Jede Achse des Würfels ist ein Eingangskanal, jeder Gitterpunkt speichert das korrigierte RGB-Tripel für diese Eingangskoordinate, und der Reader interpoliert trilinear die Ecksamples um jede eingehende Farbe. Drei Eingänge sind hier unumgänglich, da das korrigierte Rot vom eingehenden Grün und Blau abhängen kann, nicht nur vom eingehenden Rot; eine Kurve pro Kanal kann kein Kanal-Übersprechen ausdrücken, ein Würfel hingegen schon.
HotPDF erstellt den Typ-0-Stream über RegisterSampledFunction, was /Domain, /Range, /Size, /BitsPerSample und die Sample-Bytes direkt übernimmt und das Funktionsobjekt zurückgibt. Für einen standardmäßigen normierten Würfel übergeben Sie [0,1]-Grenzen auf allen drei Eingangsachsen und allen drei Ausgängen, eine N x N x N-Größe und die flache Sample-Tabelle. Der Generator validiert, ob die Byteanzahl mit dem Gitter übereinstimmt: Bei einer byte-ausgerichteten Tiefe erwartet er OutputCount x (BitsPerSample div 8) x das Produkt der Größen. Er löst eine Ausnahme aus, wenn das Array die falsche Länge hat, sodass ein falsch berechneter Stride bereits bei der Registrierung lautstark fehlschlägt, anstatt später fehlerhafte Bilder zu rendern.
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;
Die kolorimetrische Korrektheit des Würfels liegt in der Art und Weise, wie Sie ihn füllen, nicht in der PDF-Funktion. Der saubere Weg besteht darin, jeden Gitterpunkt über eine ICC-gesteuerte Konvertierung zu berechnen – dieselbe Engine, die auch einen Softproof steuert –, sodass die Zahlen im Gitter im Verhältnis zu einem definierten Quell- und Zielprofil eine Bedeutung haben. Registrieren Sie die Profile, die die Konvertierung begrenzen, mit RegisterICCProfile, was einen ICCBased-Farbraum (1, 3 oder 4 Komponenten) aufzeichnet und einen Ressourcennamen zurückgibt, den Sie an den Inhalt anhängen können, den die LUT speist. Die Typ-0-Funktion trägt die Interpolationstabelle; das ICC-Profil trägt die Bedeutung der Endpunkte.
Der 1D-Fall: Eine Schmuckfarben-Tönungskonvertierung
Separations-Farbräume stützen sich auf dieselbe Maschinerie für eine völlig andere Aufgabe. Ein Separations-Farbraum, definiert in ISO 32000-1 §8.6.6.4, stellt ein einzelnes Farbmittel dar, beispielsweise eine Schmuckfarbe wie Pantone oder einen Lack, indem er einen Namen mit einer Tönungskonvertierung (tint transform) verknüpft: eine Funktion, die den eindimensionalen Tönungswert (0 für keine Tinte bis 1 für volle Tinte) auf einen alternativen Farbraum abbildet, den das Gerät tatsächlich rendern kann, üblicherweise CMYK. Diese Tönungskonvertierung ist häufig eine Typ-0-Funktion, und in diesem Fall hat das Gitter genau eine Eingangsachse.
Dies ist der deutliche Kontrast zur 3D-LUT. Eine Schmuckfarbe entspricht einem einzigen Freiheitsgrad, sodass ihre Tönungskonvertierung einen einzigen Eingang benötigt und das Gitter eine Linie von Samples ist, von denen jedes den CMYK-Wert (oder einen anderen alternativen Wert) bei dieser Tönungsstufe enthält. Der RGB-Würfel benötigt drei Eingänge, da sein Bereich dreidimensional ist und die Kanäle interagieren. Gleicher Funktionstyp, gleiche Interpolationsregeln, unterschiedliche Dimensionalität; die Spezifikation verwendet einen Evaluator wieder und überlässt es /Size zu entscheiden, ob Sie eine Linie, eine Ebene oder einen Würfel durchlaufen. HotPDF kapselt die gesamte Separation in RegisterSeparationLUT, was die Typ-0-Tönungskonvertierung mit einem Eingang intern aus einem flachen Byte-Array erstellt und den Farbraum-Ressourcennamen zurückgibt.
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;
Die Anzahl der Samples muss einer ganzen Zahl von Gitterpunkten entsprechen: ein positives Vielfaches der Komponentenanzahl des alternativen Farbraums und mindestens zwei Punkte, damit ein Segment zum Interpolieren vorhanden ist. Wenn Sie drei Byte pro Punkt für eine CMYK-Alternative übergeben, lehnt der Aufruf dies ab. Dies ist dieselbe defensive Validierung, die auch der 3D-Generator anwendet, was man von einer Funktion erwartet, die andernfalls beim Drucken stillschweigend fehlschlagen würde.
Wo dieselbe Maschinerie wieder auftaucht
Sobald man Typ 0 als generische Interpolationstabelle versteht, wirken zwei weitere Gerätesteuerungsfunktionen nicht mehr wie Spezialfälle. Eine Transferfunktion passt Komponentenwerte auf ihrem Weg zum Ausgabegerät an und ist im Grunde nur eine Funktion pro Kanal. HotPDF registriert sie als ExtGState über RegisterTransferFunctionState, was entweder eine kombinierte Funktion oder ein Array von Funktionen pro Kanal akzeptiert. Da diese Funktionen gewöhnliche Funktionsobjekte sind, können Sie ihnen genau das THPDFStreamObject übergeben, das RegisterSampledFunction zurückgibt, und eine Transferkurve über eine abgetastete Tabelle anstelle einer Formel steuern.
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;
Unterfarbenreduktion (Undercolor Removal, UCR) und Schwarzaufbau (Black Generation) gehören zur selben Familie. Wenn ein Gerät RGB in CMYK umwandelt, entscheidet es, wie viel der Grau-Komponente als schwarze Tinte gedruckt werden soll. Die Spezifikation drückt diese Entscheidung als Funktion aus – die Einträge /BG2 und /UCR2 eines Grafikzustand-Dictionaries –, jeweils als Kurve mit einem Eingang vom berechneten Grau zu einer Schwarzmenge. Dies sind ebenfalls Typ-0-Funktionen, wenn Sie eine gemessene Kurve anstelle einer analytischen wünschen, die auf dieselbe Weise über RegisterSampledFunction erstellt und im Grafikzustand platziert werden. Die wichtigste Lehre daraus ist, dass die PDF-Funktion niemals der Ort ist, an dem das Farbmanagement stattfindet; sie ist die Lookup-Tabelle, die eine Entscheidung trägt, die Sie mit einer echten Farb-Engine getroffen haben, und Typ 0 ist der einzige Funktionstyp, der flexibel genug ist, um jede Entscheidung zu tragen.
Für ein umfassenderes Bild davon, wie Schriftarten, Bilder und Farbressourcen in ein fertiges Dokument ausgegeben werden, lesen Sie unseren Leitfaden zur Berichtsausgabe mit Schriftarten und Bildern. Wenn die Ausgabe eine Archivierungs- oder Druck-Preflight-Prüfung bestehen muss, bestimmen die in der PDF/A-, PDF/X- und PDF/UA-Validierungsanleitung behandelten Regeln für Farbräume und Ausgabeabsichten (Output Intents), welche dieser Funktionen zulässig sind und wie Gerätefarben gekennzeichnet werden müssen. All dies wird in der HotPDF-Komponente für Delphi und C++Builder ausgeliefert, zusammen mit den Schattierungs-, ICC- und Separations-APIs, die auf demselben Typ-0-Kern aufbauen.