| OLD | NEW |
| (Empty) |
| 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 #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, | |
| 125 const TIFFDisplay *display, float *refWhite) | |
| 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 { | |
| 185 int32 i; | |
| 186 | |
| 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 | |
| 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); | |
| 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*)( | |
| 226 (uint8*) ycbcr+TIFFroundup_32(sizeof (TIFFYCbCrToRGB), sizeof (long)));
| |
| 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], 2
55); | |
| 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: */ | |
| 280 /* | |
| 281 * Local Variables: | |
| 282 * mode: c | |
| 283 * c-basic-offset: 8 | |
| 284 * fill-column: 78 | |
| 285 * End: | |
| 286 */ | |
| 287 | |
| OLD | NEW |