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