]>
Commit | Line | Data |
---|---|---|
7da02538 VZ |
1 | /* $Header$ */ |
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 | float gamma; | |
125 | ||
126 | cielab->range = CIELABTORGB_TABLE_RANGE; | |
127 | ||
128 | _TIFFmemcpy(&cielab->display, display, sizeof(TIFFDisplay)); | |
129 | ||
130 | /* Red */ | |
131 | gamma = 1.0F / 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.0F / 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.0F / 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))) | |
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 |