Update to 2.0.0 tree from current Fremantle build
[opencv] / 3rdparty / libtiff / tif_color.c
1 /* $Id: tif_color.c,v 1.1 2005-06-17 13:54:52 vp153 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 TIFFCIELabToXYZ(TIFFCIELabToRGB *cielab, uint32 l, int32 a, int32 b,
47                 float *X, float *Y, float *Z)
48 {
49         float L = (float)l * 100.0F / 255.0F;
50         float cby, tmp;
51
52         if( L < 8.856F ) {
53                 *Y = (L * cielab->Y0) / 903.292F;
54                 cby = 7.787F * (*Y / cielab->Y0) + 16.0F / 116.0F;
55         } else {
56                 cby = (L + 16.0F) / 116.0F;
57                 *Y = cielab->Y0 * cby * cby * cby;
58         }
59
60         tmp = (float)a / 500.0F + cby;
61         if( tmp < 0.2069F )
62                 *X = cielab->X0 * (tmp - 0.13793F) / 7.787F;
63         else    
64                 *X = cielab->X0 * tmp * tmp * tmp;
65
66         tmp = cby - (float)b / 200.0F;
67         if( tmp < 0.2069F )
68                 *Z = cielab->Z0 * (tmp - 0.13793F) / 7.787F;
69         else    
70                 *Z = cielab->Z0 * tmp * tmp * tmp;
71 }
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 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         float *matrix = &cielab->display.d_mat[0][0];
84
85         /* Multiply through the matrix to get luminosity values. */
86         Yr =  matrix[0] * X + matrix[1] * Y + matrix[2] * Z;
87         Yg =  matrix[3] * X + matrix[4] * Y + matrix[5] * Z;
88         Yb =  matrix[6] * X + matrix[7] * Y + matrix[8] * Z;
89
90         /* Clip input */
91         Yr = TIFFmax( Yr, cielab->display.d_Y0R );
92         Yg = TIFFmax( Yg, cielab->display.d_Y0G );
93         Yb = TIFFmax( Yb, cielab->display.d_Y0B );
94
95         /* Turn luminosity to colour value. */
96         i = TIFFmin(cielab->range,
97                     (int)((Yr - cielab->display.d_Y0R) / cielab->rstep));
98         *r = RINT(cielab->Yr2r[i]);
99
100         i = TIFFmin(cielab->range,
101                     (int)((Yg - cielab->display.d_Y0G) / cielab->gstep));
102         *g = RINT(cielab->Yg2g[i]);
103
104         i = TIFFmin(cielab->range,
105                     (int)((Yb - cielab->display.d_Y0B) / cielab->bstep));
106         *b = RINT(cielab->Yb2b[i]);
107
108         /* Clip output. */
109         *r = TIFFmin( *r, cielab->display.d_Vrwr );
110         *g = TIFFmin( *g, cielab->display.d_Vrwg );
111         *b = TIFFmin( *b, cielab->display.d_Vrwb );
112 }
113 #undef RINT
114
115 /* 
116  * Allocate conversion state structures and make look_up tables for
117  * the Yr,Yb,Yg <=> r,g,b conversions.
118  */
119 int
120 TIFFCIELabToRGBInit(TIFFCIELabToRGB* cielab,
121                     TIFFDisplay *display, float *refWhite)
122 {
123         int i;
124         double gamma;
125
126         cielab->range = CIELABTORGB_TABLE_RANGE;
127
128         _TIFFmemcpy(&cielab->display, display, sizeof(TIFFDisplay));
129
130         /* Red */
131         gamma = 1.0 / cielab->display.d_gammaR ;
132         cielab->rstep =
133                 (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
134         for(i = 0; i <= cielab->range; i++) {
135                 cielab->Yr2r[i] = cielab->display.d_Vrwr
136                     * ((float)pow((double)i / cielab->range, gamma));
137         }
138
139         /* Green */
140         gamma = 1.0 / cielab->display.d_gammaG ;
141         cielab->gstep =
142             (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
143         for(i = 0; i <= cielab->range; i++) {
144                 cielab->Yg2g[i] = cielab->display.d_Vrwg
145                     * ((float)pow((double)i / cielab->range, gamma));
146         }
147
148         /* Blue */
149         gamma = 1.0 / cielab->display.d_gammaB ;
150         cielab->bstep =
151             (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
152         for(i = 0; i <= cielab->range; i++) {
153                 cielab->Yb2b[i] = cielab->display.d_Vrwb
154                     * ((float)pow((double)i / cielab->range, gamma));
155         }
156
157         /* Init reference white point */
158         cielab->X0 = refWhite[0];
159         cielab->Y0 = refWhite[1];
160         cielab->Z0 = refWhite[2];
161
162         return 0;
163 }
164
165 /* 
166  * Convert color value from the YCbCr space to CIE XYZ.
167  * The colorspace conversion algorithm comes from the IJG v5a code;
168  * see below for more information on how it works.
169  */
170 #define SHIFT                   16
171 #define FIX(x)                  ((int32)((x) * (1L<<SHIFT) + 0.5))
172 #define ONE_HALF                ((int32)(1<<(SHIFT-1)))
173 #define Code2V(c, RB, RW, CR)   ((((c)-(int32)(RB))*(float)(CR))/(float)(((RW)-(RB)) ? ((RW)-(RB)) : 1))
174 #define CLAMP(f,min,max)        ((f)<(min)?(min):(f)>(max)?(max):(f))
175
176 void
177 TIFFYCbCrtoRGB(TIFFYCbCrToRGB *ycbcr, uint32 Y, int32 Cb, int32 Cr,
178                uint32 *r, uint32 *g, uint32 *b)
179 {
180         /* XXX: Only 8-bit YCbCr input supported for now */
181         Y = CLAMP(Y, 0, 255), Cb = CLAMP(Cb, 0, 255), Cr = CLAMP(Cr, 0, 255);
182
183         *r = ycbcr->clamptab[ycbcr->Y_tab[Y] + ycbcr->Cr_r_tab[Cr]];
184         *g = ycbcr->clamptab[ycbcr->Y_tab[Y]
185             + (int)((ycbcr->Cb_g_tab[Cb] + ycbcr->Cr_g_tab[Cr]) >> SHIFT)];
186         *b = ycbcr->clamptab[ycbcr->Y_tab[Y] + ycbcr->Cb_b_tab[Cb]];
187 }
188
189 /*
190  * Initialize the YCbCr->RGB conversion tables.  The conversion
191  * is done according to the 6.0 spec:
192  *
193  *    R = Y + Cr*(2 - 2*LumaRed)
194  *    B = Y + Cb*(2 - 2*LumaBlue)
195  *    G =   Y
196  *        - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen
197  *        - LumaRed*Cr*(2-2*LumaRed)/LumaGreen
198  *
199  * To avoid floating point arithmetic the fractional constants that
200  * come out of the equations are represented as fixed point values
201  * in the range 0...2^16.  We also eliminate multiplications by
202  * pre-calculating possible values indexed by Cb and Cr (this code
203  * assumes conversion is being done for 8-bit samples).
204  */
205 int
206 TIFFYCbCrToRGBInit(TIFFYCbCrToRGB* ycbcr, float *luma, float *refBlackWhite)
207 {
208     TIFFRGBValue* clamptab;
209     int i;
210     
211 #define LumaRed     luma[0]
212 #define LumaGreen   luma[1]
213 #define LumaBlue    luma[2]
214
215     clamptab = (TIFFRGBValue*)(
216         (tidata_t) ycbcr+TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long)));
217     _TIFFmemset(clamptab, 0, 256);              /* v < 0 => 0 */
218     ycbcr->clamptab = (clamptab += 256);
219     for (i = 0; i < 256; i++)
220         clamptab[i] = (TIFFRGBValue) i;
221     _TIFFmemset(clamptab+256, 255, 2*256);      /* v > 255 => 255 */
222     ycbcr->Cr_r_tab = (int*) (clamptab + 3*256);
223     ycbcr->Cb_b_tab = ycbcr->Cr_r_tab + 256;
224     ycbcr->Cr_g_tab = (int32*) (ycbcr->Cb_b_tab + 256);
225     ycbcr->Cb_g_tab = ycbcr->Cr_g_tab + 256;
226     ycbcr->Y_tab = ycbcr->Cb_g_tab + 256;
227
228     { float f1 = 2-2*LumaRed;           int32 D1 = FIX(f1);
229       float f2 = LumaRed*f1/LumaGreen;  int32 D2 = -FIX(f2);
230       float f3 = 2-2*LumaBlue;          int32 D3 = FIX(f3);
231       float f4 = LumaBlue*f3/LumaGreen; int32 D4 = -FIX(f4);
232       int x;
233
234 #undef LumaBlue
235 #undef LumaGreen
236 #undef LumaRed
237       
238       /*
239        * i is the actual input pixel value in the range 0..255
240        * Cb and Cr values are in the range -128..127 (actually
241        * they are in a range defined by the ReferenceBlackWhite
242        * tag) so there is some range shifting to do here when
243        * constructing tables indexed by the raw pixel data.
244        */
245       for (i = 0, x = -128; i < 256; i++, x++) {
246             int32 Cr = (int32)Code2V(x, refBlackWhite[4] - 128.0F,
247                             refBlackWhite[5] - 128.0F, 127);
248             int32 Cb = (int32)Code2V(x, refBlackWhite[2] - 128.0F,
249                             refBlackWhite[3] - 128.0F, 127);
250
251             ycbcr->Cr_r_tab[i] = (int32)((D1*Cr + ONE_HALF)>>SHIFT);
252             ycbcr->Cb_b_tab[i] = (int32)((D3*Cb + ONE_HALF)>>SHIFT);
253             ycbcr->Cr_g_tab[i] = D2*Cr;
254             ycbcr->Cb_g_tab[i] = D4*Cb + ONE_HALF;
255             ycbcr->Y_tab[i] =
256                     (int32)Code2V(x + 128, refBlackWhite[0], refBlackWhite[1], 255);
257       }
258     }
259
260     return 0;
261 }
262 #undef  CLAMP
263 #undef  Code2V
264 #undef  SHIFT
265 #undef  ONE_HALF
266 #undef  FIX
267
268 /* vim: set ts=8 sts=8 sw=8 noet: */