2 * Copyright (c) 1988-1997 Sam Leffler
3 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
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.
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.
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
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.
34 * Color space conversion routines.
41 * Convert color value from the CIE L*a*b* 1976 space to CIE XYZ.
44 TIFFCIELabToXYZ(TIFFCIELabToRGB
*cielab
, uint32 l
, int32 a
, int32 b
,
45 float *X
, float *Y
, float *Z
)
47 float L
= (float)l
* 100.0F
/ 255.0F
;
51 *Y
= (L
* cielab
->Y0
) / 903.292F
;
52 cby
= 7.787F
* (*Y
/ cielab
->Y0
) + 16.0F
/ 116.0F
;
54 cby
= (L
+ 16.0F
) / 116.0F
;
55 *Y
= cielab
->Y0
* cby
* cby
* cby
;
58 tmp
= (float)a
/ 500.0F
+ cby
;
60 *X
= cielab
->X0
* (tmp
- 0.13793F
) / 7.787F
;
62 *X
= cielab
->X0
* tmp
* tmp
* tmp
;
64 tmp
= cby
- (float)b
/ 200.0F
;
66 *Z
= cielab
->Z0
* (tmp
- 0.13793F
) / 7.787F
;
68 *Z
= cielab
->Z0
* tmp
* tmp
* tmp
;
71 #define RINT(R) ((uint32)((R)>0?((R)+0.5):((R)-0.5)))
73 * Convert color value from the XYZ space to RGB.
76 TIFFXYZToRGB(TIFFCIELabToRGB
*cielab
, float X
, float Y
, float Z
,
77 uint32
*r
, uint32
*g
, uint32
*b
)
81 float *matrix
= &cielab
->display
.d_mat
[0][0];
83 /* Multiply through the matrix to get luminosity values. */
84 Yr
= matrix
[0] * X
+ matrix
[1] * Y
+ matrix
[2] * Z
;
85 Yg
= matrix
[3] * X
+ matrix
[4] * Y
+ matrix
[5] * Z
;
86 Yb
= matrix
[6] * X
+ matrix
[7] * Y
+ matrix
[8] * Z
;
89 Yr
= TIFFmax(Yr
, cielab
->display
.d_Y0R
);
90 Yg
= TIFFmax(Yg
, cielab
->display
.d_Y0G
);
91 Yb
= TIFFmax(Yb
, cielab
->display
.d_Y0B
);
93 /* Avoid overflow in case of wrong input values */
94 Yr
= TIFFmin(Yr
, cielab
->display
.d_YCR
);
95 Yg
= TIFFmin(Yg
, cielab
->display
.d_YCG
);
96 Yb
= TIFFmin(Yb
, cielab
->display
.d_YCB
);
98 /* Turn luminosity to colour value. */
99 i
= (int)((Yr
- cielab
->display
.d_Y0R
) / cielab
->rstep
);
100 i
= TIFFmin(cielab
->range
, i
);
101 *r
= RINT(cielab
->Yr2r
[i
]);
103 i
= (int)((Yg
- cielab
->display
.d_Y0G
) / cielab
->gstep
);
104 i
= TIFFmin(cielab
->range
, i
);
105 *g
= RINT(cielab
->Yg2g
[i
]);
107 i
= (int)((Yb
- cielab
->display
.d_Y0B
) / cielab
->bstep
);
108 i
= TIFFmin(cielab
->range
, i
);
109 *b
= RINT(cielab
->Yb2b
[i
]);
112 *r
= TIFFmin(*r
, cielab
->display
.d_Vrwr
);
113 *g
= TIFFmin(*g
, cielab
->display
.d_Vrwg
);
114 *b
= TIFFmin(*b
, cielab
->display
.d_Vrwb
);
119 * Allocate conversion state structures and make look_up tables for
120 * the Yr,Yb,Yg <=> r,g,b conversions.
123 TIFFCIELabToRGBInit(TIFFCIELabToRGB
* cielab
,
124 const TIFFDisplay
*display
, float *refWhite
)
129 cielab
->range
= CIELABTORGB_TABLE_RANGE
;
131 _TIFFmemcpy(&cielab
->display
, display
, sizeof(TIFFDisplay
));
134 dfGamma
= 1.0 / cielab
->display
.d_gammaR
;
136 (cielab
->display
.d_YCR
- cielab
->display
.d_Y0R
) / cielab
->range
;
137 for(i
= 0; i
<= cielab
->range
; i
++) {
138 cielab
->Yr2r
[i
] = cielab
->display
.d_Vrwr
139 * ((float)pow((double)i
/ cielab
->range
, dfGamma
));
143 dfGamma
= 1.0 / cielab
->display
.d_gammaG
;
145 (cielab
->display
.d_YCR
- cielab
->display
.d_Y0R
) / cielab
->range
;
146 for(i
= 0; i
<= cielab
->range
; i
++) {
147 cielab
->Yg2g
[i
] = cielab
->display
.d_Vrwg
148 * ((float)pow((double)i
/ cielab
->range
, dfGamma
));
152 dfGamma
= 1.0 / cielab
->display
.d_gammaB
;
154 (cielab
->display
.d_YCR
- cielab
->display
.d_Y0R
) / cielab
->range
;
155 for(i
= 0; i
<= cielab
->range
; i
++) {
156 cielab
->Yb2b
[i
] = cielab
->display
.d_Vrwb
157 * ((float)pow((double)i
/ cielab
->range
, dfGamma
));
160 /* Init reference white point */
161 cielab
->X0
= refWhite
[0];
162 cielab
->Y0
= refWhite
[1];
163 cielab
->Z0
= refWhite
[2];
169 * Convert color value from the YCbCr space to RGB.
170 * The colorspace conversion algorithm comes from the IJG v5a code;
171 * see below for more information on how it works.
174 #define FIX(x) ((int32)((x) * (1L<<SHIFT) + 0.5))
175 #define ONE_HALF ((int32)(1<<(SHIFT-1)))
176 #define Code2V(c, RB, RW, CR) ((((c)-(int32)(RB))*(float)(CR))/(float)(((RW)-(RB)!=0) ? ((RW)-(RB)) : 1))
177 #define CLAMP(f,min,max) ((f)<(min)?(min):(f)>(max)?(max):(f))
178 #define HICLAMP(f,max) ((f)>(max)?(max):(f))
181 TIFFYCbCrtoRGB(TIFFYCbCrToRGB
*ycbcr
, uint32 Y
, int32 Cb
, int32 Cr
,
182 uint32
*r
, uint32
*g
, uint32
*b
)
186 /* XXX: Only 8-bit YCbCr input supported for now */
188 Cb
= CLAMP(Cb
, 0, 255);
189 Cr
= CLAMP(Cr
, 0, 255);
191 i
= ycbcr
->Y_tab
[Y
] + ycbcr
->Cr_r_tab
[Cr
];
192 *r
= CLAMP(i
, 0, 255);
194 + (int)((ycbcr
->Cb_g_tab
[Cb
] + ycbcr
->Cr_g_tab
[Cr
]) >> SHIFT
);
195 *g
= CLAMP(i
, 0, 255);
196 i
= ycbcr
->Y_tab
[Y
] + ycbcr
->Cb_b_tab
[Cb
];
197 *b
= CLAMP(i
, 0, 255);
200 /* Clamp function for sanitization purposes. Normally clamping should not */
201 /* occur for well behaved chroma and refBlackWhite coefficients */
202 static float CLAMPw(float v
, float vmin
, float vmax
)
206 /* printf("%f clamped to %f\n", v, vmin); */
211 /* printf("%f clamped to %f\n", v, vmax); */
218 * Initialize the YCbCr->RGB conversion tables. The conversion
219 * is done according to the 6.0 spec:
221 * R = Y + Cr*(2 - 2*LumaRed)
222 * B = Y + Cb*(2 - 2*LumaBlue)
224 * - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen
225 * - LumaRed*Cr*(2-2*LumaRed)/LumaGreen
227 * To avoid floating point arithmetic the fractional constants that
228 * come out of the equations are represented as fixed point values
229 * in the range 0...2^16. We also eliminate multiplications by
230 * pre-calculating possible values indexed by Cb and Cr (this code
231 * assumes conversion is being done for 8-bit samples).
234 TIFFYCbCrToRGBInit(TIFFYCbCrToRGB
* ycbcr
, float *luma
, float *refBlackWhite
)
236 TIFFRGBValue
* clamptab
;
239 #define LumaRed luma[0]
240 #define LumaGreen luma[1]
241 #define LumaBlue luma[2]
243 clamptab
= (TIFFRGBValue
*)(
244 (uint8
*) ycbcr
+TIFFroundup_32(sizeof (TIFFYCbCrToRGB
), sizeof (long)));
245 _TIFFmemset(clamptab
, 0, 256); /* v < 0 => 0 */
246 ycbcr
->clamptab
= (clamptab
+= 256);
247 for (i
= 0; i
< 256; i
++)
248 clamptab
[i
] = (TIFFRGBValue
) i
;
249 _TIFFmemset(clamptab
+256, 255, 2*256); /* v > 255 => 255 */
250 ycbcr
->Cr_r_tab
= (int*) (clamptab
+ 3*256);
251 ycbcr
->Cb_b_tab
= ycbcr
->Cr_r_tab
+ 256;
252 ycbcr
->Cr_g_tab
= (int32
*) (ycbcr
->Cb_b_tab
+ 256);
253 ycbcr
->Cb_g_tab
= ycbcr
->Cr_g_tab
+ 256;
254 ycbcr
->Y_tab
= ycbcr
->Cb_g_tab
+ 256;
256 { float f1
= 2-2*LumaRed
; int32 D1
= FIX(CLAMP(f1
,0.0F
,2.0F
));
257 float f2
= LumaRed
*f1
/LumaGreen
; int32 D2
= -FIX(CLAMP(f2
,0.0F
,2.0F
));
258 float f3
= 2-2*LumaBlue
; int32 D3
= FIX(CLAMP(f3
,0.0F
,2.0F
));
259 float f4
= LumaBlue
*f3
/LumaGreen
; int32 D4
= -FIX(CLAMP(f4
,0.0F
,2.0F
));
267 * i is the actual input pixel value in the range 0..255
268 * Cb and Cr values are in the range -128..127 (actually
269 * they are in a range defined by the ReferenceBlackWhite
270 * tag) so there is some range shifting to do here when
271 * constructing tables indexed by the raw pixel data.
273 for (i
= 0, x
= -128; i
< 256; i
++, x
++) {
274 int32 Cr
= (int32
)CLAMPw(Code2V(x
, refBlackWhite
[4] - 128.0F
,
275 refBlackWhite
[5] - 128.0F
, 127),
276 -128.0F
* 32, 128.0F
* 32);
277 int32 Cb
= (int32
)CLAMPw(Code2V(x
, refBlackWhite
[2] - 128.0F
,
278 refBlackWhite
[3] - 128.0F
, 127),
279 -128.0F
* 32, 128.0F
* 32);
281 ycbcr
->Cr_r_tab
[i
] = (int32
)((D1
*Cr
+ ONE_HALF
)>>SHIFT
);
282 ycbcr
->Cb_b_tab
[i
] = (int32
)((D3
*Cb
+ ONE_HALF
)>>SHIFT
);
283 ycbcr
->Cr_g_tab
[i
] = D2
*Cr
;
284 ycbcr
->Cb_g_tab
[i
] = D4
*Cb
+ ONE_HALF
;
286 (int32
)CLAMPw(Code2V(x
+ 128, refBlackWhite
[0], refBlackWhite
[1], 255),
287 -128.0F
* 32, 128.0F
* 32);
300 /* vim: set ts=8 sts=8 sw=8 noet: */