Bilder

Eingebundene Bilder wurden oft unabhängig vom restlichen Dokument erstellt, und haben ihre eigenen Farbkorrekturinformationen. Darum ist es in PDF möglich, die Farbkorrektur eingebundener Bilder separat einzustellen. Zudem kann man für die allfällige Konversion von RGB nach CMYK festlegen, ob möglichst auf exakte Farbumsetzung, Erhaltung der Farbsättigung, oder Erhaltung des photographischen Eindrucks geachtet werden soll.

Farbkorrektur

Um eine vom Dokumentstandard abweichende Farbkorrektur für das Bild festzulegen, müssen wir im Bildobjekt den /ColorSpace Eintrag ändern. Dieser war bisher auf /DeviceGray, /DeviceRGB, /DeviceCMYK oder ein Array mit einem /Indexed Farbmodell.

/DeviceGray, /DeviceRGB oder /DeviceCMYK werden einfach durch eine Umrechnungstabelle oder einen Verweis auf ein ICC-Profil ersetzt.

Beispiel:

10 0 obj
<<
/Type /XObject
/Subtype /Image
/Width 800
/Height 600
/ColorSpace [/ICCBased 11 0 R]
/BitsPerComponent 8
/Interpolate true
/Filter [/ASCII85Decode /DCTDecode]
/Length 35654
>>
stream
...~>
endstream
endobj

Bei indizierten Farbräumen ist die Sache ein klein wenig kniffliger. Diese sind bekanntlich als Arrays angegeben, von denen der erste Eintrag /Indexed ist. Der zweite Eintrag war in unserem Fall bisher immer /DeviceRGB. Diesen Eintrag müssen wir ersetzen.

Beispiel:

/ColorSpace [/Indexed [/ICCBased 11 0 R] 3 <FF000000FF000000FFFFFFFF>]

Vorsicht: Beim Alphakanal muss /ColorSpace auf /DeviceGray gesetzt werden. /CalGray und /ICCBased sind hier nicht erlaubt (und machen auch wenig Sinn).

Umrechnungspriorität

Das Dictionary des Bildobjekts kann einen Eintrag /Intent haben, der auf die bekannten Intents gesetzt werden kann. Als Daumenregel kann man sich merken:

Bei Formaten, die typischerweise Fotos enthalten (insbesondere JPEG), eignet sich /Perceptual als Standard.

Bei allen anderen Formaten eignet sich /RelativeColorimetric als Standard.

Daten aus Bildern ermitteln

Die Umrechnungspriorität müssen wir von Hand einstellen. Farbkorrekturinformationen hingegen sind zuweilen in den Bilddateien abgelegt. Wir müssen sie nur rausfischen.

JPEG

Bei JPEG herrscht leider ein gewisses Chaos. Das JFIF Format enthält überhaupt keine Farbkorrekturinformationen. Das EXIF Format erlaubt zwar, solche abzulegen, jedoch sind diese unzuverlässig: Zum einen handelt es sich meist nur um Schätzwerte, und zum anderen oft um die Werte der Kamera. Wir brauchen aber die Werte des Bildschirms, an dem das Bild aufbereitet wurde.

ICC hat schliesslich eine eigene Erweiterung veröffentlicht, welche es ermöglicht, ein ICC-Profil in eine JPEG-Datei einzubetten. Um diese Information zu ermitteln, müssen wir alle Metadatenblöcke des JPEG anschauen. Zur Erinnerung: Sobald wir dabei auf einen Block mit dem Marker <FF DA> stossen, können wir die Verarbeitung abbrechen. Nach diesem Block folgend die komprimierten Bilddaten.

Das ICC-Profil ist in einem oder mehreren Metadatenblöcken abgelegt. Diese Blöcke haben den Marker <FF E2>. Der Aufbau ist wie folgt:

Position Grösse Typ Wert
01 Byte uint8 immer 0xFF
11 Byte uint8 immer 0xE2
22 Byte uint16 Blockgrösse
411 Byte char ASCII-String ICC_PROFILE
151 Byte uint8 immer 0
161 Byte uint8 Blocknummer
171 Byte uint8 Blockanzahl
18Blockgrösse - 16 * ICC-Profildaten

Der String ICC_PROFILE am Anfang soll den Block zweifelsfrei als ICC-Block markieren. Es können auch andere Daten in einem Block mit dem <FF E2> Marker abgelegt sein, da es sich nicht um einen offiziellen Standard des JPEG Komitees handelt.

Ist die Blockanzahl 1, so können wir die Profildaten aus diesem Block 1:1 übernehmen. Ansonsten müssen wir die Profildaten aller ICC-Blocks aneinanderhängen, und zwar in der Reihenfolge, die mit der Blocknummer vorgegeben ist (aufsteigend ab 1).

Die (allenfalls zusammengesetzten) Profildaten sind die unveränderten Daten einer ICC-Datei. Das heisst, die Daten können in einen Stream gepackt werden, der dann mit /ICCBased referenziert werden kann (den /N Eintrag im Stream des ICC-Profils nicht vergessen).

PNG

PNG bietet drei Möglichkeiten, die Farbkorrektur anzugeben: sRGB-Deklaration, ICC-Profile und Chromatizitätsdeklaration.

sRGB-Deklaration

Das ist die einfachste Methode. Enthält das PNG einen Block mit Marker sRGB (auf Gross- und Kleinschreibung achten), so wird das sRGB-Farbmodell verwendet. Man kann dementsprechend /CalRGB bzw. /CalGray mit den zu sRGB passenden Zahlen verwenden. Falls dieser Block vorkommt, sollten ICC-Profile oder Chromatizitätsdeklarationen ignoriert werden.

Position Grösse Typ Wert
04 Byte uint32 Blockgrösse
44 Byte char immer sRGB
81 Byte uint8 Umrechnungspriorität
94 Byte uint32 Prüfsumme

Wie man sieht, kann in diesem Block (und nur in diesem Block) eine bevorzugte Umrechnungspriorität definiert werden. Folgende vier Werte sind möglich:

0/Perceptual
1/RelativeColorimetric
2/Saturation
3/AbsoluteColorimetric

ICC-Profil

Enthält das PNG einen Block mit Marker iCCP, so enthält dieser ein ICC-Profil. Der Blockaufbau ist wie folgt:

Position Grösse Typ Wert
04 Byte uint32 Blockgrösse
44 Byte char immer iCCP
8* char Profilname
*1 Byte uint8 immer 0
*1 Byte uint8 Kompression
** * ICC-Profildaten
*4 Byte uint32 Prüfsumme

Der Profilname ist in ISO Latin-1 kodiert, für uns aber nicht wichtig. Entscheidend ist, dass der Name selbst kein 0-Byte enthalten kann. Das erste 0-Byte innerhalb der Blockdaten ist folglich der oben erwähnte uint8 mit Wert 0. Das ist die einzige Möglichkeit, die Länge des Profilnamens zu ermitteln.

Die Kompressionsmethode ist immer 0, was Deflate bedeutet. Das heisst, wir können die Profildaten 1:1 in einen Stream packen, und den /FlateDecode Filter angeben. Den Stream können wir dann mit /ICCBased referenzieren.

Chromatizität

Die ist die letzte Möglichkeit, falls weder eine sRGB-Deklaration noch ein ICC-Profil vorhanden sind. In diesem Fall haben wir zwei Blöcke. Einen cHRM Block mit Weisspunkt und Matrix, und einen gAMA Block mit dem Gammawert. Falls nur einer der beiden vorhanden ist (was nicht der Fall sein sollte), so kann man die sRGB-Werte für den fehlenden Block verwenden.

gAMA
Position Grösse Typ Wert
04 Byte uint32 Blockgrösse
44 Byte char immer gAMA
84 Byte uint32 Gammawert (invers)
124 Byte uint32 Prüfsumme

Der inverse Gammawert ist eine Ganzzahl auf einer Skala von 0 - 100'000. Den Wert für das PDF erhalten wir folglich, indem wir mit einer Fliesskommadivision 100'000 durch den Wert aus dem PNG teilen:

$$g_{pdf} = \frac{100000}{g_{png}}$$

cHRM

Der cHRM Block enthält die Chromatizität des Weisspunkts und der verwendeten Rot- Grün- und Blautöne. Dies ist eine weitere CIE-Norm, die mit zwei Koordinaten x und y ausgedrückt wird. Um Verwechslungen mit dem XYZ-Farbraum zu vermeiden, werden für Chromatizität immer Kleinbuchstaben, für XYZ immer Grossbuchstaben verwendet.

Position Grösse Typ Wert
04 Byte uint32 Blockgrösse
44 Byte char immer cHRM
84 Byte uint32 xw
124 Byte uint32 yw
164 Byte uint32 xr
204 Byte uint32 yr
244 Byte uint32 xg
284 Byte uint32 yg
324 Byte uint32 xb
364 Byte uint32 yb
404 Byte uint32 Prüfsumme

Ähnlich wie im gAMA Block handelt es sich um vorzeichenlose Ganzzahlen auf einer Skala von 0 - 100'000. Anders als bei gAMA sind sie aber nicht invers. Folglich müssen wir diesmal die Zahlen mit Fliesskommadivisionen durch 100'000 teilen.

$$x_{pdf} = \frac{x_{png}}{100000}$$ $$y_{pdf} = \frac{y_{png}}{100000}$$

Wenn wir dies erledigt haben, können wir die Werte in den XYZ-Farbraum umrechnen.

Zunächst müssen wir die XYZ-Werte des Weisspunkts berechnen:

$$X_w = \frac{x_w}{y_w}$$ $$Y_w = 1$$ $$Z_w = \frac{1 - x_w - y_w}{y_w}$$

Für die Grundfarben brauchen wir folgenden Formelsatz:

$$z_r = 1 - x_r - y_r$$ $$z_g = 1 - x_g - y_g$$ $$z_b = 1 - x_b - y_b$$ $$\begin{bmatrix} S_r && S_g && S_b \end{bmatrix} = \begin{bmatrix} x_r && y_r && z_r \\\\ x_g && y_g && z_g \\\\ x_b && y_b && z_b \end{bmatrix}^{-1} \begin{bmatrix} X_w && Y_w && Z_w \end{bmatrix}$$ $$\begin{bmatrix} X_r && Y_r && Z_r \end{bmatrix} = \begin{bmatrix} x_r && y_r && z_r \end{bmatrix} S_r$$ $$\begin{bmatrix} X_g && Y_g && Z_g \end{bmatrix} = \begin{bmatrix} x_g && y_g && z_g \end{bmatrix} S_g$$ $$\begin{bmatrix} X_b && Y_b && Z_b \end{bmatrix} = \begin{bmatrix} x_b && y_b && z_b \end{bmatrix} S_b$$

Wie man sieht, enthalten die Formeln leider eine invertierte Matrix. Das macht die arithmetische Variante recht kompliziert:

$$z_r = 1 - x_r - y_r$$ $$z_g = 1 - x_g - y_g$$ $$z_b = 1 - x_b - y_b$$ $$m_{xr} = y_gz_b - z_gy_b$$ $$m_{xg} = z_ry_b - y_rz_b$$ $$m_{xb} = y_rz_g - z_ry_g$$ $$d = m_{xr}x_r + m_{xg}x_g + m_{xb}x_b$$ $$S_r = \frac{m_{xr}X_w + (y_bZ_w - z_b) x_g + (z_g - y_gZ_w) x_b}{d}$$ $$S_g = \frac{m_{xg}X_w + (y_rZ_w - z_r) x_b + (z_b - y_bZ_w) x_r}{d}$$ $$S_b = \frac{m_{xb}X_w + (y_gZ_w - z_g)x_r + (z_r - y_rZ_w) x_g}{d}$$ $$X_r = x_rS_r$$ $$Y_r = y_rS_r$$ $$Z_r = z_rS_r$$ $$X_g = x_gS_g$$ $$Y_g = y_gS_g$$ $$Z_g = z_gS_g$$ $$X_b = x_bS_b$$ $$Y_b = y_bS_b$$ $$Z_b = z_bS_b$$

Damit können wir nun die Werte für /CalRGB zusammenstellen. Ins /WhitePoint Array, gehören nacheinander die Werte Xw, Yw und Zw. Ins /Matrix Array nacheinander die Werte Xr, Yr, Zr, Xg, Yg, Zg, Xb, Yb und Zb.

Diskussion

Geben Sie Ihren Kommentar ein. Wiki-Syntax ist zugelassen:
K​ K Q​ N M
 
grafik/farbkorrektur/bilder.txt · Zuletzt geändert: 2013/02/17 19:03 (Externe Bearbeitung)
 
Falls nicht anders bezeichnet, ist der Inhalt dieses Wikis unter der folgenden Lizenz veröffentlicht: CC0 1.0 Universal
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki