• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 void
TIFFCIELabToXYZ(TIFFCIELabToRGB * cielab,uint32 l,int32 a,int32 b,float * X,float * Y,float * Z)44 TIFFCIELabToXYZ(TIFFCIELabToRGB *cielab, uint32 l, int32 a, int32 b,
45 		float *X, float *Y, float *Z)
46 {
47 	float L = (float)l * 100.0F / 255.0F;
48 	float cby, tmp;
49 
50 	if( L < 8.856F ) {
51 		*Y = (L * cielab->Y0) / 903.292F;
52 		cby = 7.787F * (*Y / cielab->Y0) + 16.0F / 116.0F;
53 	} else {
54 		cby = (L + 16.0F) / 116.0F;
55 		*Y = cielab->Y0 * cby * cby * cby;
56 	}
57 
58 	tmp = (float)a / 500.0F + cby;
59 	if( tmp < 0.2069F )
60 		*X = cielab->X0 * (tmp - 0.13793F) / 7.787F;
61 	else
62 		*X = cielab->X0 * tmp * tmp * tmp;
63 
64 	tmp = cby - (float)b / 200.0F;
65 	if( tmp < 0.2069F )
66 		*Z = cielab->Z0 * (tmp - 0.13793F) / 7.787F;
67 	else
68 		*Z = cielab->Z0 * tmp * tmp * tmp;
69 }
70 
71 #define RINT(R) ((uint32)((R)>0?((R)+0.5):((R)-0.5)))
72 /*
73  * Convert color value from the XYZ space to RGB.
74  */
75 void
TIFFXYZToRGB(TIFFCIELabToRGB * cielab,float X,float Y,float Z,uint32 * r,uint32 * g,uint32 * b)76 TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z,
77 	     uint32 *r, uint32 *g, uint32 *b)
78 {
79 	int i;
80 	float Yr, Yg, Yb;
81 	float *matrix = &cielab->display.d_mat[0][0];
82 
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;
87 
88 	/* Clip input */
89 	Yr = TIFFmax(Yr, cielab->display.d_Y0R);
90 	Yg = TIFFmax(Yg, cielab->display.d_Y0G);
91 	Yb = TIFFmax(Yb, cielab->display.d_Y0B);
92 
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);
97 
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]);
102 
103 	i = (int)((Yg - cielab->display.d_Y0G) / cielab->gstep);
104 	i = TIFFmin(cielab->range, i);
105 	*g = RINT(cielab->Yg2g[i]);
106 
107 	i = (int)((Yb - cielab->display.d_Y0B) / cielab->bstep);
108 	i = TIFFmin(cielab->range, i);
109 	*b = RINT(cielab->Yb2b[i]);
110 
111 	/* Clip output. */
112 	*r = TIFFmin(*r, cielab->display.d_Vrwr);
113 	*g = TIFFmin(*g, cielab->display.d_Vrwg);
114 	*b = TIFFmin(*b, cielab->display.d_Vrwb);
115 }
116 #undef RINT
117 
118 /*
119  * Allocate conversion state structures and make look_up tables for
120  * the Yr,Yb,Yg <=> r,g,b conversions.
121  */
122 int
TIFFCIELabToRGBInit(TIFFCIELabToRGB * cielab,const TIFFDisplay * display,float * refWhite)123 TIFFCIELabToRGBInit(TIFFCIELabToRGB* cielab,
124 		    const TIFFDisplay *display, float *refWhite)
125 {
126 	int i;
127 	double dfGamma;
128 
129 	cielab->range = CIELABTORGB_TABLE_RANGE;
130 
131 	_TIFFmemcpy(&cielab->display, display, sizeof(TIFFDisplay));
132 
133 	/* Red */
134 	dfGamma = 1.0 / cielab->display.d_gammaR ;
135 	cielab->rstep =
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));
140 	}
141 
142 	/* Green */
143 	dfGamma = 1.0 / cielab->display.d_gammaG ;
144 	cielab->gstep =
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));
149 	}
150 
151 	/* Blue */
152 	dfGamma = 1.0 / cielab->display.d_gammaB ;
153 	cielab->bstep =
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));
158 	}
159 
160 	/* Init reference white point */
161 	cielab->X0 = refWhite[0];
162 	cielab->Y0 = refWhite[1];
163 	cielab->Z0 = refWhite[2];
164 
165 	return 0;
166 }
167 
168 /*
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.
172  */
173 #define	SHIFT			16
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))
179 
180 void
TIFFYCbCrtoRGB(TIFFYCbCrToRGB * ycbcr,uint32 Y,int32 Cb,int32 Cr,uint32 * r,uint32 * g,uint32 * b)181 TIFFYCbCrtoRGB(TIFFYCbCrToRGB *ycbcr, uint32 Y, int32 Cb, int32 Cr,
182 	       uint32 *r, uint32 *g, uint32 *b)
183 {
184 	int32 i;
185 
186 	/* XXX: Only 8-bit YCbCr input supported for now */
187 	Y = HICLAMP(Y, 255);
188 	Cb = CLAMP(Cb, 0, 255);
189 	Cr = CLAMP(Cr, 0, 255);
190 
191 	i = ycbcr->Y_tab[Y] + ycbcr->Cr_r_tab[Cr];
192 	*r = CLAMP(i, 0, 255);
193 	i = ycbcr->Y_tab[Y]
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);
198 }
199 
200 /* Clamp function for sanitization purposes. Normally clamping should not */
201 /* occur for well behaved chroma and refBlackWhite coefficients */
CLAMPw(float v,float vmin,float vmax)202 static float CLAMPw(float v, float vmin, float vmax)
203 {
204     if( v < vmin )
205     {
206         /* printf("%f clamped to %f\n", v, vmin); */
207         return vmin;
208     }
209     if( v > vmax )
210     {
211         /* printf("%f clamped to %f\n", v, vmax); */
212         return vmax;
213     }
214     return v;
215 }
216 
217 /*
218  * Initialize the YCbCr->RGB conversion tables.  The conversion
219  * is done according to the 6.0 spec:
220  *
221  *    R = Y + Cr*(2 - 2*LumaRed)
222  *    B = Y + Cb*(2 - 2*LumaBlue)
223  *    G =   Y
224  *        - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen
225  *        - LumaRed*Cr*(2-2*LumaRed)/LumaGreen
226  *
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).
232  */
233 int
TIFFYCbCrToRGBInit(TIFFYCbCrToRGB * ycbcr,float * luma,float * refBlackWhite)234 TIFFYCbCrToRGBInit(TIFFYCbCrToRGB* ycbcr, float *luma, float *refBlackWhite)
235 {
236     TIFFRGBValue* clamptab;
237     int i;
238 
239 #define LumaRed	    luma[0]
240 #define LumaGreen   luma[1]
241 #define LumaBlue    luma[2]
242 
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;
255 
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));
260       int x;
261 
262 #undef LumaBlue
263 #undef LumaGreen
264 #undef LumaRed
265 
266       /*
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.
272        */
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);
280 
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;
285 	    ycbcr->Y_tab[i] =
286 		    (int32)CLAMPw(Code2V(x + 128, refBlackWhite[0], refBlackWhite[1], 255),
287                                   -128.0F * 32, 128.0F * 32);
288       }
289     }
290 
291     return 0;
292 }
293 #undef	HICLAMP
294 #undef	CLAMP
295 #undef	Code2V
296 #undef	SHIFT
297 #undef	ONE_HALF
298 #undef	FIX
299 
300 /* vim: set ts=8 sts=8 sw=8 noet: */
301 /*
302  * Local Variables:
303  * mode: c
304  * c-basic-offset: 8
305  * fill-column: 78
306  * End:
307  */
308