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