Line data Source code
1 : /*
2 : * Copyright (c) 1988-1997 Sam Leffler
3 : * Copyright (c) 1991-1997 Silicon Graphics, Inc.
4 : *
5 : * Permission to use, copy, modify, distribute, and sell this software and
6 : * its documentation for any purpose is hereby granted without fee, provided
7 : * that (i) the above copyright notices and this permission notice appear in
8 : * all copies of the software and related documentation, and (ii) the names of
9 : * Sam Leffler and Silicon Graphics may not be used in any advertising or
10 : * publicity relating to the software without the specific, prior written
11 : * permission of Sam Leffler and Silicon Graphics.
12 : *
13 : * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
14 : * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
15 : * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16 : *
17 : * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
18 : * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
19 : * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 : * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
21 : * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22 : * OF THIS SOFTWARE.
23 : */
24 :
25 : /*
26 : * CIE L*a*b* to CIE XYZ and CIE XYZ to RGB conversion routines are taken
27 : * from the VIPS library (http://www.vips.ecs.soton.ac.uk) with
28 : * the permission of John Cupitt, the VIPS author.
29 : */
30 :
31 : /*
32 : * TIFF Library.
33 : *
34 : * Color space conversion routines.
35 : */
36 :
37 : #include "tiffiop.h"
38 : #include <math.h>
39 :
40 : /*
41 : * Convert color value from the CIE L*a*b* 1976 space to CIE XYZ.
42 : */
43 : TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW
44 1 : void TIFFCIELabToXYZ(TIFFCIELabToRGB *cielab, uint32_t l, int32_t a, int32_t b,
45 : float *X, float *Y, float *Z)
46 : {
47 : /*
48 : * Keep the historical signed a * 256 and b * 256 scaling. Out-of-range
49 : * callers may trigger UBSan signed-overflow reports here, but this
50 : * per-pixel path intentionally does not add extra handling; see !926 for
51 : * details.
52 : */
53 1 : TIFFCIELab16ToXYZ(cielab, l * 257U, a * 256, b * 256, X, Y, Z);
54 1 : }
55 :
56 : /*
57 : * For CIELab encoded in 16 bits, L is an unsigned integer range [0,65535].
58 : * The a* and b* components are signed integers range [-32768,32767]. The 16
59 : * bit chrominance values are encoded as 256 times the 1976 CIE a* and b*
60 : * values
61 : */
62 1 : void TIFFCIELab16ToXYZ(TIFFCIELabToRGB *cielab, uint32_t l, int32_t a,
63 : int32_t b, float *X, float *Y, float *Z)
64 : {
65 1 : float L = (float)l * 100.0f / 65535.0f;
66 : float cby, tmp;
67 :
68 1 : if (L < 8.856f)
69 : {
70 0 : *Y = (L * cielab->Y0) / 903.292f;
71 0 : cby = 7.787f * (*Y / cielab->Y0) + 16.0f / 116.0f;
72 : }
73 : else
74 : {
75 1 : cby = (L + 16.0f) / 116.0f;
76 1 : *Y = cielab->Y0 * cby * cby * cby;
77 : }
78 :
79 1 : tmp = (float)a / 256.0f / 500.0f + cby;
80 1 : if (tmp < 0.2069f)
81 0 : *X = cielab->X0 * (tmp - 0.13793f) / 7.787f;
82 : else
83 1 : *X = cielab->X0 * tmp * tmp * tmp;
84 :
85 1 : tmp = cby - (float)b / 256.0f / 200.0f;
86 1 : if (tmp < 0.2069f)
87 0 : *Z = cielab->Z0 * (tmp - 0.13793f) / 7.787f;
88 : else
89 1 : *Z = cielab->Z0 * tmp * tmp * tmp;
90 1 : }
91 :
92 : #define RINT(R) ((uint32_t)((R) > 0 ? ((R) + 0.5f) : ((R) - 0.5f)))
93 : /*
94 : * Convert color value from the XYZ space to RGB.
95 : */
96 1 : void TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z,
97 : uint32_t *r, uint32_t *g, uint32_t *b)
98 : {
99 : size_t i;
100 : float Yr, Yg, Yb;
101 1 : float *matrix = &cielab->display.d_mat[0][0];
102 :
103 : /* Multiply through the matrix to get luminosity values. */
104 1 : Yr = matrix[0] * X + matrix[1] * Y + matrix[2] * Z;
105 1 : Yg = matrix[3] * X + matrix[4] * Y + matrix[5] * Z;
106 1 : Yb = matrix[6] * X + matrix[7] * Y + matrix[8] * Z;
107 :
108 : /* Clip input */
109 1 : Yr = TIFFmax(Yr, cielab->display.d_Y0R);
110 1 : Yg = TIFFmax(Yg, cielab->display.d_Y0G);
111 1 : Yb = TIFFmax(Yb, cielab->display.d_Y0B);
112 :
113 : /* Avoid overflow in case of wrong input values */
114 1 : Yr = TIFFmin(Yr, cielab->display.d_YCR);
115 1 : Yg = TIFFmin(Yg, cielab->display.d_YCG);
116 1 : Yb = TIFFmin(Yb, cielab->display.d_YCB);
117 :
118 : /* Turn luminosity to colour value. */
119 1 : i = (size_t)((Yr - cielab->display.d_Y0R) / cielab->rstep);
120 1 : i = TIFFmin((size_t)cielab->range, i);
121 1 : *r = RINT(cielab->Yr2r[i]);
122 :
123 1 : i = (size_t)((Yg - cielab->display.d_Y0G) / cielab->gstep);
124 1 : i = TIFFmin((size_t)cielab->range, i);
125 1 : *g = RINT(cielab->Yg2g[i]);
126 :
127 1 : i = (size_t)((Yb - cielab->display.d_Y0B) / cielab->bstep);
128 1 : i = TIFFmin((size_t)cielab->range, i);
129 1 : *b = RINT(cielab->Yb2b[i]);
130 :
131 : /* Clip output. */
132 1 : *r = TIFFmin(*r, cielab->display.d_Vrwr);
133 1 : *g = TIFFmin(*g, cielab->display.d_Vrwg);
134 1 : *b = TIFFmin(*b, cielab->display.d_Vrwb);
135 1 : }
136 : #undef RINT
137 :
138 : /*
139 : * Allocate conversion state structures and make look_up tables for
140 : * the Yr,Yb,Yg <=> r,g,b conversions.
141 : */
142 1 : int TIFFCIELabToRGBInit(TIFFCIELabToRGB *cielab, const TIFFDisplay *display,
143 : float *refWhite)
144 : {
145 : size_t i;
146 : double dfGamma;
147 :
148 1 : cielab->range = CIELABTORGB_TABLE_RANGE;
149 :
150 1 : _TIFFmemcpy(&cielab->display, display, sizeof(TIFFDisplay));
151 :
152 : /* Red */
153 1 : dfGamma = 1.0 / (double)cielab->display.d_gammaR;
154 1 : cielab->rstep =
155 1 : (cielab->display.d_YCR - cielab->display.d_Y0R) / (float)cielab->range;
156 1502 : for (i = 0; i <= (size_t)cielab->range; i++)
157 : {
158 1501 : cielab->Yr2r[i] = (float)cielab->display.d_Vrwr *
159 1501 : ((float)pow((double)i / cielab->range, dfGamma));
160 : }
161 :
162 : /* Green */
163 1 : dfGamma = 1.0 / (double)cielab->display.d_gammaG;
164 1 : cielab->gstep =
165 1 : (cielab->display.d_YCR - cielab->display.d_Y0R) / (float)cielab->range;
166 1502 : for (i = 0; i <= (size_t)cielab->range; i++)
167 : {
168 1501 : cielab->Yg2g[i] = (float)cielab->display.d_Vrwg *
169 1501 : ((float)pow((double)i / cielab->range, dfGamma));
170 : }
171 :
172 : /* Blue */
173 1 : dfGamma = 1.0 / (double)cielab->display.d_gammaB;
174 1 : cielab->bstep =
175 1 : (cielab->display.d_YCR - cielab->display.d_Y0R) / (float)cielab->range;
176 1502 : for (i = 0; i <= (size_t)cielab->range; i++)
177 : {
178 1501 : cielab->Yb2b[i] = (float)cielab->display.d_Vrwb *
179 1501 : ((float)pow((double)i / cielab->range, dfGamma));
180 : }
181 :
182 : /* Init reference white point */
183 1 : cielab->X0 = refWhite[0];
184 1 : cielab->Y0 = refWhite[1];
185 1 : cielab->Z0 = refWhite[2];
186 :
187 1 : return 0;
188 : }
189 :
190 : /*
191 : * Convert color value from the YCbCr space to RGB.
192 : * The colorspace conversion algorithm comes from the IJG v5a code;
193 : * see below for more information on how it works.
194 : */
195 : #define SHIFT 16
196 : #define FIX(x) ((int32_t)((double)(x) * (1L << SHIFT) + 0.5))
197 : #define ONE_HALF ((int32_t)(1 << (SHIFT - 1)))
198 : #define Code2V(c, RB, RW, CR) \
199 : (((float)((c) - (int32_t)(RB)) * (float)(CR)) / \
200 : ((!TIFF_FLOAT_EQ((RW), (RB))) ? ((RW) - (RB)) : 1.0f))
201 : /* !((f)>=(min)) written that way to deal with NaN */
202 : #define CLAMP(f, min, max) \
203 : ((!((f) >= (min))) ? (min) : (f) > (max) ? (max) : (f))
204 : #define HICLAMP(f, max) ((f) > (max) ? (max) : (f))
205 :
206 65097 : void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *ycbcr, uint32_t Y, int32_t Cb, int32_t Cr,
207 : uint32_t *r, uint32_t *g, uint32_t *b)
208 : {
209 : int32_t i;
210 :
211 : /* XXX: Only 8-bit YCbCr input supported for now */
212 65097 : Y = HICLAMP(Y, 255);
213 65097 : Cb = CLAMP(Cb, 0, 255);
214 65097 : Cr = CLAMP(Cr, 0, 255);
215 :
216 65097 : i = ycbcr->Y_tab[Y] + ycbcr->Cr_r_tab[Cr];
217 65097 : *r = (uint32_t)CLAMP(i, 0, 255);
218 65097 : i = ycbcr->Y_tab[Y] +
219 65097 : ((ycbcr->Cb_g_tab[Cb] + ycbcr->Cr_g_tab[Cr]) >> SHIFT);
220 65097 : *g = (uint32_t)CLAMP(i, 0, 255);
221 65097 : i = ycbcr->Y_tab[Y] + ycbcr->Cb_b_tab[Cb];
222 65097 : *b = (uint32_t)CLAMP(i, 0, 255);
223 65097 : }
224 :
225 : /* Clamp function for sanitization purposes. Normally clamping should not */
226 : /* occur for well behaved chroma and refBlackWhite coefficients */
227 13056 : static float CLAMPw(float v, float vmin, float vmax)
228 : {
229 13056 : if (v < vmin)
230 : {
231 : /* printf("%f clamped to %f\n", v, vmin); */
232 0 : return vmin;
233 : }
234 13056 : if (v > vmax)
235 : {
236 : /* printf("%f clamped to %f\n", v, vmax); */
237 0 : return vmax;
238 : }
239 13056 : return v;
240 : }
241 :
242 : /*
243 : * Initialize the YCbCr->RGB conversion tables. The conversion
244 : * is done according to the 6.0 spec:
245 : *
246 : * R = Y + Cr*(2 - 2*LumaRed)
247 : * B = Y + Cb*(2 - 2*LumaBlue)
248 : * G = Y
249 : * - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen
250 : * - LumaRed*Cr*(2-2*LumaRed)/LumaGreen
251 : *
252 : * To avoid floating point arithmetic the fractional constants that
253 : * come out of the equations are represented as fixed point values
254 : * in the range 0...2^16. We also eliminate multiplications by
255 : * pre-calculating possible values indexed by Cb and Cr (this code
256 : * assumes conversion is being done for 8-bit samples).
257 : */
258 17 : int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB *ycbcr, float *luma, float *refBlackWhite)
259 : {
260 : TIFFRGBValue *clamptab;
261 : int i;
262 :
263 : #define LumaRed luma[0]
264 : #define LumaGreen luma[1]
265 : #define LumaBlue luma[2]
266 :
267 17 : clamptab =
268 : (uint8_t *)ycbcr + TIFFroundup_32(sizeof(TIFFYCbCrToRGB), sizeof(long));
269 17 : _TIFFmemset(clamptab, 0, 256); /* v < 0 => 0 */
270 17 : ycbcr->clamptab = (clamptab += 256);
271 4369 : for (i = 0; i < 256; i++)
272 4352 : clamptab[i] = (TIFFRGBValue)i;
273 17 : _TIFFmemset(clamptab + 256, 255, 2 * 256); /* v > 255 => 255 */
274 17 : ycbcr->Cr_r_tab = (int *)(clamptab + 3 * 256);
275 17 : ycbcr->Cb_b_tab = ycbcr->Cr_r_tab + 256;
276 17 : ycbcr->Cr_g_tab = (int32_t *)(ycbcr->Cb_b_tab + 256);
277 17 : ycbcr->Cb_g_tab = ycbcr->Cr_g_tab + 256;
278 17 : ycbcr->Y_tab = ycbcr->Cb_g_tab + 256;
279 :
280 : {
281 17 : float f1 = 2 - 2 * LumaRed;
282 17 : int32_t D1 = FIX(CLAMP(f1, 0.0f, 2.0f));
283 17 : float f2 = LumaRed * f1 / LumaGreen;
284 17 : int32_t D2 = -FIX(CLAMP(f2, 0.0f, 2.0f));
285 17 : float f3 = 2 - 2 * LumaBlue;
286 17 : int32_t D3 = FIX(CLAMP(f3, 0.0f, 2.0f));
287 17 : float f4 = LumaBlue * f3 / LumaGreen;
288 17 : int32_t D4 = -FIX(CLAMP(f4, 0.0f, 2.0f));
289 : int x;
290 :
291 : #undef LumaBlue
292 : #undef LumaGreen
293 : #undef LumaRed
294 :
295 : /*
296 : * i is the actual input pixel value in the range 0..255
297 : * Cb and Cr values are in the range -128..127 (actually
298 : * they are in a range defined by the ReferenceBlackWhite
299 : * tag) so there is some range shifting to do here when
300 : * constructing tables indexed by the raw pixel data.
301 : */
302 4369 : for (i = 0, x = -128; i < 256; i++, x++)
303 : {
304 4352 : int32_t Cr = (int32_t)CLAMPw(Code2V(x, refBlackWhite[4] - 128.0f,
305 : refBlackWhite[5] - 128.0f, 127),
306 : -128.0f * 32, 128.0f * 32);
307 4352 : int32_t Cb = (int32_t)CLAMPw(Code2V(x, refBlackWhite[2] - 128.0f,
308 : refBlackWhite[3] - 128.0f, 127),
309 : -128.0f * 32, 128.0f * 32);
310 :
311 4352 : ycbcr->Cr_r_tab[i] = (int32_t)((D1 * Cr + ONE_HALF) >> SHIFT);
312 4352 : ycbcr->Cb_b_tab[i] = (int32_t)((D3 * Cb + ONE_HALF) >> SHIFT);
313 4352 : ycbcr->Cr_g_tab[i] = D2 * Cr;
314 4352 : ycbcr->Cb_g_tab[i] = D4 * Cb + ONE_HALF;
315 4352 : ycbcr->Y_tab[i] = (int32_t)CLAMPw(
316 4352 : Code2V(x + 128, refBlackWhite[0], refBlackWhite[1], 255),
317 : -128.0f * 32, 128.0f * 32);
318 : }
319 : }
320 :
321 17 : return 0;
322 : }
323 : #undef HICLAMP
324 : #undef CLAMP
325 : #undef Code2V
326 : #undef SHIFT
327 : #undef ONE_HALF
328 : #undef FIX
|