J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 3 | * |
| 4 | * This code is free software; you can redistribute it and/or modify it |
| 5 | * under the terms of the GNU General Public License version 2 only, as |
| 6 | * published by the Free Software Foundation. Sun designates this |
| 7 | * particular file as subject to the "Classpath" exception as provided |
| 8 | * by Sun in the LICENSE file that accompanied this code. |
| 9 | * |
| 10 | * This code is distributed in the hope that it will be useful, but WITHOUT |
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 13 | * version 2 for more details (a copy is included in the LICENSE file that |
| 14 | * accompanied this code). |
| 15 | * |
| 16 | * You should have received a copy of the GNU General Public License version |
| 17 | * 2 along with this work; if not, write to the Free Software Foundation, |
| 18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| 19 | * |
| 20 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 21 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 22 | * have any questions. |
| 23 | */ |
| 24 | |
| 25 | // This file is available under and governed by the GNU General Public |
| 26 | // License version 2 only, as published by the Free Software Foundation. |
| 27 | // However, the following notice accompanied the original version of this |
| 28 | // file: |
| 29 | // |
| 30 | // |
| 31 | // Little cms |
| 32 | // Copyright (C) 1998-2006 Marti Maria |
| 33 | // |
| 34 | // Permission is hereby granted, free of charge, to any person obtaining |
| 35 | // a copy of this software and associated documentation files (the "Software"), |
| 36 | // to deal in the Software without restriction, including without limitation |
| 37 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 38 | // and/or sell copies of the Software, and to permit persons to whom the Software |
| 39 | // is furnished to do so, subject to the following conditions: |
| 40 | // |
| 41 | // The above copyright notice and this permission notice shall be included in |
| 42 | // all copies or substantial portions of the Software. |
| 43 | // |
| 44 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 45 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO |
| 46 | // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 47 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| 48 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| 49 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 50 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 51 | |
| 52 | // inter PCS conversions XYZ <-> CIE L* a* b* |
| 53 | |
| 54 | #include "lcms.h" |
| 55 | |
| 56 | /* |
| 57 | |
| 58 | |
| 59 | CIE 15:2004 CIELab is defined as: |
| 60 | |
| 61 | L* = 116*f(Y/Yn) - 16 0 <= L* <= 100 |
| 62 | a* = 500*[f(X/Xn) - f(Y/Yn)] |
| 63 | b* = 200*[f(Y/Yn) - f(Z/Zn)] |
| 64 | |
| 65 | and |
| 66 | |
| 67 | f(t) = t^(1/3) 1 >= t > (24/116)^3 |
| 68 | (841/108)*t + (16/116) 0 <= t <= (24/116)^3 |
| 69 | |
| 70 | |
| 71 | Reverse transform is: |
| 72 | |
| 73 | X = Xn*[a* / 500 + (L* + 16) / 116] ^ 3 if (X/Xn) > (24/116) |
| 74 | = Xn*(a* / 500 + L* / 116) / 7.787 if (X/Xn) <= (24/116) |
| 75 | |
| 76 | |
| 77 | |
| 78 | Following ICC. PCS in Lab is coded as: |
| 79 | |
| 80 | 8 bit Lab PCS: |
| 81 | |
| 82 | L* 0..100 into a 0..ff byte. |
| 83 | a* t + 128 range is -128.0 +127.0 |
| 84 | b* |
| 85 | |
| 86 | 16 bit Lab PCS: |
| 87 | |
| 88 | L* 0..100 into a 0..ff00 word. |
| 89 | a* t + 128 range is -128.0 +127.9961 |
| 90 | b* |
| 91 | |
| 92 | |
| 93 | We are always playing with 16 bits-data, so I will ignore the |
| 94 | 8-bits encoding scheme. |
| 95 | |
| 96 | |
| 97 | Interchange Space Component Actual Range Encoded Range |
| 98 | CIE XYZ X 0 -> 1.99997 0x0000 -> 0xffff |
| 99 | CIE XYZ Y 0 -> 1.99997 0x0000 -> 0xffff |
| 100 | CIE XYZ Z 0 -> 1.99997 0x0000 -> 0xffff |
| 101 | |
| 102 | Version 2,3 |
| 103 | ----------- |
| 104 | |
| 105 | CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xff00 |
| 106 | CIELAB (16 bit) a* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffff |
| 107 | CIELAB (16 bit) b* -128.0 -> +127.996 0x0000 -> 0x8000 -> 0xffff |
| 108 | |
| 109 | |
| 110 | Version 4 |
| 111 | --------- |
| 112 | |
| 113 | CIELAB (16 bit) L* 0 -> 100.0 0x0000 -> 0xffff |
| 114 | CIELAB (16 bit) a* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff |
| 115 | CIELAB (16 bit) b* -128.0 -> +127 0x0000 -> 0x8080 -> 0xffff |
| 116 | |
| 117 | */ |
| 118 | |
| 119 | |
| 120 | |
| 121 | |
| 122 | // On most modern computers, D > 4 M (i.e. a division takes more than 4 |
| 123 | // multiplications worth of time), so it is probably preferable to compute |
| 124 | // a 24 bit result directly. |
| 125 | |
| 126 | // #define ITERATE 1 |
| 127 | |
| 128 | static |
| 129 | float CubeRoot(float x) |
| 130 | { |
| 131 | float fr, r; |
| 132 | int ex, shx; |
| 133 | |
| 134 | /* Argument reduction */ |
| 135 | fr = (float) frexp(x, &ex); /* separate into mantissa and exponent */ |
| 136 | shx = ex % 3; |
| 137 | |
| 138 | if (shx > 0) |
| 139 | shx -= 3; /* compute shx such that (ex - shx) is divisible by 3 */ |
| 140 | |
| 141 | ex = (ex - shx) / 3; /* exponent of cube root */ |
| 142 | fr = (float) ldexp(fr, shx); |
| 143 | |
| 144 | /* 0.125 <= fr < 1.0 */ |
| 145 | |
| 146 | #ifdef ITERATE |
| 147 | /* Compute seed with a quadratic approximation */ |
| 148 | |
| 149 | fr = (-0.46946116F * fr + 1.072302F) * fr + 0.3812513F;/* 0.5<=fr<1 */ |
| 150 | r = ldexp(fr, ex); /* 6 bits of precision */ |
| 151 | |
| 152 | /* Newton-Raphson iterations */ |
| 153 | |
| 154 | r = (float)(2.0/3.0) * r + (float)(1.0/3.0) * x / (r * r); /* 12 bits */ |
| 155 | r = (float)(2.0/3.0) * r + (float)(1.0/3.0) * x / (r * r); /* 24 bits */ |
| 156 | #else /* ITERATE */ |
| 157 | |
| 158 | /* Use quartic rational polynomial with error < 2^(-24) */ |
| 159 | |
| 160 | fr = (float) (((((45.2548339756803022511987494 * fr + |
| 161 | 192.2798368355061050458134625) * fr + |
| 162 | 119.1654824285581628956914143) * fr + |
| 163 | 13.43250139086239872172837314) * fr + |
| 164 | 0.1636161226585754240958355063) |
| 165 | / |
| 166 | ((((14.80884093219134573786480845 * fr + |
| 167 | 151.9714051044435648658557668) * fr + |
| 168 | 168.5254414101568283957668343) * fr + |
| 169 | 33.9905941350215598754191872) * fr + |
| 170 | 1.0)); |
| 171 | r = (float) ldexp(fr, ex); /* 24 bits of precision */ |
| 172 | #endif |
| 173 | return r; |
| 174 | } |
| 175 | |
| 176 | static |
| 177 | double f(double t) |
| 178 | { |
| 179 | |
| 180 | const double Limit = (24.0/116.0) * (24.0/116.0) * (24.0/116.0); |
| 181 | |
| 182 | if (t <= Limit) |
| 183 | return (841.0/108.0) * t + (16.0/116.0); |
| 184 | else |
| 185 | return CubeRoot((float) t); |
| 186 | } |
| 187 | |
| 188 | |
| 189 | static |
| 190 | double f_1(double t) |
| 191 | { |
| 192 | const double Limit = (24.0/116.0); |
| 193 | |
| 194 | if (t <= Limit) |
| 195 | { |
| 196 | double tmp; |
| 197 | |
| 198 | tmp = (108.0/841.0) * (t - (16.0/116.0)); |
| 199 | if (tmp <= 0.0) return 0.0; |
| 200 | else return tmp; |
| 201 | } |
| 202 | |
| 203 | return t * t * t; |
| 204 | } |
| 205 | |
| 206 | |
| 207 | |
| 208 | void LCMSEXPORT cmsXYZ2Lab(LPcmsCIEXYZ WhitePoint, LPcmsCIELab Lab, const cmsCIEXYZ* xyz) |
| 209 | { |
| 210 | double fx, fy, fz; |
| 211 | |
| 212 | if (xyz -> X == 0 && xyz -> Y == 0 && xyz -> Z == 0) |
| 213 | { |
| 214 | Lab -> L = 0; |
| 215 | Lab -> a = 0; |
| 216 | Lab -> b = 0; |
| 217 | return; |
| 218 | } |
| 219 | |
| 220 | if (WhitePoint == NULL) |
| 221 | WhitePoint = cmsD50_XYZ(); |
| 222 | |
| 223 | fx = f(xyz->X / WhitePoint->X); |
| 224 | fy = f(xyz->Y / WhitePoint->Y); |
| 225 | fz = f(xyz->Z / WhitePoint->Z); |
| 226 | |
| 227 | Lab->L = 116.0* fy - 16.; |
| 228 | |
| 229 | Lab->a = 500.0*(fx - fy); |
| 230 | Lab->b = 200.0*(fy - fz); |
| 231 | } |
| 232 | |
| 233 | |
| 234 | |
| 235 | void cmsXYZ2LabEncoded(WORD XYZ[3], WORD Lab[3]) |
| 236 | { |
| 237 | Fixed32 X, Y, Z; |
| 238 | double x, y, z, L, a, b; |
| 239 | double fx, fy, fz; |
| 240 | Fixed32 wL, wa, wb; |
| 241 | |
| 242 | X = (Fixed32) XYZ[0] << 1; |
| 243 | Y = (Fixed32) XYZ[1] << 1; |
| 244 | Z = (Fixed32) XYZ[2] << 1; |
| 245 | |
| 246 | |
| 247 | if (X==0 && Y==0 && Z==0) { |
| 248 | |
| 249 | Lab[0] = 0; |
| 250 | Lab[1] = Lab[2] = 0x8000; |
| 251 | return; |
| 252 | } |
| 253 | |
| 254 | // PCS is in D50 |
| 255 | |
| 256 | |
| 257 | x = FIXED_TO_DOUBLE(X) / D50X; |
| 258 | y = FIXED_TO_DOUBLE(Y) / D50Y; |
| 259 | z = FIXED_TO_DOUBLE(Z) / D50Z; |
| 260 | |
| 261 | |
| 262 | fx = f(x); |
| 263 | fy = f(y); |
| 264 | fz = f(z); |
| 265 | |
| 266 | L = 116.* fy - 16.; |
| 267 | |
| 268 | a = 500.*(fx - fy); |
| 269 | b = 200.*(fy - fz); |
| 270 | |
| 271 | a += 128.; |
| 272 | b += 128.; |
| 273 | |
| 274 | wL = (int) (L * 652.800 + .5); |
| 275 | wa = (int) (a * 256.0 + .5); |
| 276 | wb = (int) (b * 256.0 + .5); |
| 277 | |
| 278 | |
| 279 | Lab[0] = Clamp_L(wL); |
| 280 | Lab[1] = Clamp_ab(wa); |
| 281 | Lab[2] = Clamp_ab(wb); |
| 282 | |
| 283 | |
| 284 | } |
| 285 | |
| 286 | |
| 287 | |
| 288 | |
| 289 | |
| 290 | |
| 291 | void LCMSEXPORT cmsLab2XYZ(LPcmsCIEXYZ WhitePoint, LPcmsCIEXYZ xyz, const cmsCIELab* Lab) |
| 292 | { |
| 293 | double x, y, z; |
| 294 | |
| 295 | if (Lab -> L <= 0) { |
| 296 | xyz -> X = 0; |
| 297 | xyz -> Y = 0; |
| 298 | xyz -> Z = 0; |
| 299 | return; |
| 300 | } |
| 301 | |
| 302 | |
| 303 | if (WhitePoint == NULL) |
| 304 | WhitePoint = cmsD50_XYZ(); |
| 305 | |
| 306 | y = (Lab-> L + 16.0) / 116.0; |
| 307 | x = y + 0.002 * Lab -> a; |
| 308 | z = y - 0.005 * Lab -> b; |
| 309 | |
| 310 | xyz -> X = f_1(x) * WhitePoint -> X; |
| 311 | xyz -> Y = f_1(y) * WhitePoint -> Y; |
| 312 | xyz -> Z = f_1(z) * WhitePoint -> Z; |
| 313 | |
| 314 | } |
| 315 | |
| 316 | |
| 317 | |
| 318 | void cmsLab2XYZEncoded(WORD Lab[3], WORD XYZ[3]) |
| 319 | { |
| 320 | double L, a, b; |
| 321 | double X, Y, Z, x, y, z; |
| 322 | |
| 323 | |
| 324 | L = ((double) Lab[0] * 100.0) / 65280.0; |
| 325 | if (L==0.0) { |
| 326 | |
| 327 | XYZ[0] = 0; XYZ[1] = 0; XYZ[2] = 0; |
| 328 | return; |
| 329 | } |
| 330 | |
| 331 | a = ((double) Lab[1] / 256.0) - 128.0; |
| 332 | b = ((double) Lab[2] / 256.0) - 128.0; |
| 333 | |
| 334 | y = (L + 16.) / 116.0; |
| 335 | x = y + 0.002 * a; |
| 336 | z = y - 0.005 * b; |
| 337 | |
| 338 | X = f_1(x) * D50X; |
| 339 | Y = f_1(y) * D50Y; |
| 340 | Z = f_1(z) * D50Z; |
| 341 | |
| 342 | // Convert to 1.15 fixed format PCS |
| 343 | |
| 344 | |
| 345 | XYZ[0] = _cmsClampWord((int) floor(X * 32768.0 + 0.5)); |
| 346 | XYZ[1] = _cmsClampWord((int) floor(Y * 32768.0 + 0.5)); |
| 347 | XYZ[2] = _cmsClampWord((int) floor(Z * 32768.0 + 0.5)); |
| 348 | |
| 349 | |
| 350 | } |
| 351 | |
| 352 | static |
| 353 | double L2float3(WORD v) |
| 354 | { |
| 355 | Fixed32 fix32; |
| 356 | |
| 357 | fix32 = (Fixed32) v; |
| 358 | return (double) fix32 / 652.800; |
| 359 | } |
| 360 | |
| 361 | |
| 362 | // the a/b part |
| 363 | |
| 364 | static |
| 365 | double ab2float3(WORD v) |
| 366 | { |
| 367 | Fixed32 fix32; |
| 368 | |
| 369 | fix32 = (Fixed32) v; |
| 370 | return ((double) fix32/256.0)-128.0; |
| 371 | } |
| 372 | |
| 373 | static |
| 374 | WORD L2Fix3(double L) |
| 375 | { |
| 376 | return (WORD) (L * 652.800 + 0.5); |
| 377 | } |
| 378 | |
| 379 | static |
| 380 | WORD ab2Fix3(double ab) |
| 381 | { |
| 382 | return (WORD) ((ab + 128.0) * 256.0 + 0.5); |
| 383 | } |
| 384 | |
| 385 | |
| 386 | // ICC 4.0 -- ICC has changed PCS Lab encoding. |
| 387 | |
| 388 | static |
| 389 | WORD L2Fix4(double L) |
| 390 | { |
| 391 | return (WORD) (L * 655.35 + 0.5); |
| 392 | } |
| 393 | |
| 394 | static |
| 395 | WORD ab2Fix4(double ab) |
| 396 | { |
| 397 | return (WORD) ((ab + 128.0) * 257.0 + 0.5); |
| 398 | } |
| 399 | |
| 400 | static |
| 401 | double L2float4(WORD v) |
| 402 | { |
| 403 | Fixed32 fix32; |
| 404 | |
| 405 | fix32 = (Fixed32) v; |
| 406 | return (double) fix32 / 655.35; |
| 407 | } |
| 408 | |
| 409 | |
| 410 | // the a/b part |
| 411 | |
| 412 | static |
| 413 | double ab2float4(WORD v) |
| 414 | { |
| 415 | Fixed32 fix32; |
| 416 | |
| 417 | fix32 = (Fixed32) v; |
| 418 | return ((double) fix32/257.0)-128.0; |
| 419 | } |
| 420 | |
| 421 | |
| 422 | void LCMSEXPORT cmsLabEncoded2Float(LPcmsCIELab Lab, const WORD wLab[3]) |
| 423 | { |
| 424 | Lab->L = L2float3(wLab[0]); |
| 425 | Lab->a = ab2float3(wLab[1]); |
| 426 | Lab->b = ab2float3(wLab[2]); |
| 427 | } |
| 428 | |
| 429 | |
| 430 | void LCMSEXPORT cmsLabEncoded2Float4(LPcmsCIELab Lab, const WORD wLab[3]) |
| 431 | { |
| 432 | Lab->L = L2float4(wLab[0]); |
| 433 | Lab->a = ab2float4(wLab[1]); |
| 434 | Lab->b = ab2float4(wLab[2]); |
| 435 | } |
| 436 | |
| 437 | static |
| 438 | double Clamp_L_double(double L) |
| 439 | { |
| 440 | if (L < 0) L = 0; |
| 441 | if (L > 100) L = 100; |
| 442 | |
| 443 | return L; |
| 444 | } |
| 445 | |
| 446 | |
| 447 | static |
| 448 | double Clamp_ab_double(double ab) |
| 449 | { |
| 450 | if (ab < -128) ab = -128.0; |
| 451 | if (ab > +127.9961) ab = +127.9961; |
| 452 | |
| 453 | return ab; |
| 454 | } |
| 455 | |
| 456 | void LCMSEXPORT cmsFloat2LabEncoded(WORD wLab[3], const cmsCIELab* fLab) |
| 457 | { |
| 458 | cmsCIELab Lab; |
| 459 | |
| 460 | |
| 461 | Lab.L = Clamp_L_double(fLab ->L); |
| 462 | Lab.a = Clamp_ab_double(fLab ->a); |
| 463 | Lab.b = Clamp_ab_double(fLab ->b); |
| 464 | |
| 465 | wLab[0] = L2Fix3(Lab.L); |
| 466 | wLab[1] = ab2Fix3(Lab.a); |
| 467 | wLab[2] = ab2Fix3(Lab.b); |
| 468 | } |
| 469 | |
| 470 | |
| 471 | void LCMSEXPORT cmsFloat2LabEncoded4(WORD wLab[3], const cmsCIELab* fLab) |
| 472 | { |
| 473 | cmsCIELab Lab; |
| 474 | |
| 475 | |
| 476 | Lab.L = fLab ->L; |
| 477 | Lab.a = fLab ->a; |
| 478 | Lab.b = fLab ->b; |
| 479 | |
| 480 | |
| 481 | if (Lab.L < 0) Lab.L = 0; |
| 482 | if (Lab.L > 100.) Lab.L = 100.; |
| 483 | |
| 484 | if (Lab.a < -128.) Lab.a = -128.; |
| 485 | if (Lab.a > 127.) Lab.a = 127.; |
| 486 | if (Lab.b < -128.) Lab.b = -128.; |
| 487 | if (Lab.b > 127.) Lab.b = 127.; |
| 488 | |
| 489 | |
| 490 | wLab[0] = L2Fix4(Lab.L); |
| 491 | wLab[1] = ab2Fix4(Lab.a); |
| 492 | wLab[2] = ab2Fix4(Lab.b); |
| 493 | } |
| 494 | |
| 495 | |
| 496 | |
| 497 | |
| 498 | void LCMSEXPORT cmsLab2LCh(LPcmsCIELCh LCh, const cmsCIELab* Lab) |
| 499 | { |
| 500 | double a, b; |
| 501 | |
| 502 | LCh -> L = Clamp_L_double(Lab -> L); |
| 503 | |
| 504 | a = Clamp_ab_double(Lab -> a); |
| 505 | b = Clamp_ab_double(Lab -> b); |
| 506 | |
| 507 | LCh -> C = pow(a * a + b * b, 0.5); |
| 508 | |
| 509 | if (a == 0 && b == 0) |
| 510 | LCh -> h = 0; |
| 511 | else |
| 512 | LCh -> h = atan2(b, a); |
| 513 | |
| 514 | |
| 515 | LCh -> h *= (180. / M_PI); |
| 516 | |
| 517 | |
| 518 | while (LCh -> h >= 360.) // Not necessary, but included as a check. |
| 519 | LCh -> h -= 360.; |
| 520 | |
| 521 | while (LCh -> h < 0) |
| 522 | LCh -> h += 360.; |
| 523 | |
| 524 | } |
| 525 | |
| 526 | |
| 527 | |
| 528 | |
| 529 | void LCMSEXPORT cmsLCh2Lab(LPcmsCIELab Lab, const cmsCIELCh* LCh) |
| 530 | { |
| 531 | |
| 532 | double h = (LCh -> h * M_PI) / 180.0; |
| 533 | |
| 534 | Lab -> L = Clamp_L_double(LCh -> L); |
| 535 | Lab -> a = Clamp_ab_double(LCh -> C * cos(h)); |
| 536 | Lab -> b = Clamp_ab_double(LCh -> C * sin(h)); |
| 537 | |
| 538 | } |
| 539 | |
| 540 | |
| 541 | |
| 542 | |
| 543 | |
| 544 | // In XYZ All 3 components are encoded using 1.15 fixed point |
| 545 | |
| 546 | static |
| 547 | WORD XYZ2Fix(double d) |
| 548 | { |
| 549 | return (WORD) floor(d * 32768.0 + 0.5); |
| 550 | } |
| 551 | |
| 552 | |
| 553 | void LCMSEXPORT cmsFloat2XYZEncoded(WORD XYZ[3], const cmsCIEXYZ* fXYZ) |
| 554 | { |
| 555 | cmsCIEXYZ xyz; |
| 556 | |
| 557 | xyz.X = fXYZ -> X; |
| 558 | xyz.Y = fXYZ -> Y; |
| 559 | xyz.Z = fXYZ -> Z; |
| 560 | |
| 561 | |
| 562 | // Clamp to encodeable values. |
| 563 | // 1.99997 is reserved as out-of-gamut marker |
| 564 | |
| 565 | |
| 566 | if (xyz.Y <= 0) { |
| 567 | |
| 568 | xyz.X = 0; |
| 569 | xyz.Y = 0; |
| 570 | xyz.Z = 0; |
| 571 | } |
| 572 | |
| 573 | |
| 574 | if (xyz.X > 1.99996) |
| 575 | xyz.X = 1.99996; |
| 576 | |
| 577 | if (xyz.X < 0) |
| 578 | xyz.X = 0; |
| 579 | |
| 580 | if (xyz.Y > 1.99996) |
| 581 | xyz.Y = 1.99996; |
| 582 | |
| 583 | if (xyz.Y < 0) |
| 584 | xyz.Y = 0; |
| 585 | |
| 586 | |
| 587 | if (xyz.Z > 1.99996) |
| 588 | xyz.Z = 1.99996; |
| 589 | |
| 590 | if (xyz.Z < 0) |
| 591 | xyz.Z = 0; |
| 592 | |
| 593 | |
| 594 | |
| 595 | XYZ[0] = XYZ2Fix(xyz.X); |
| 596 | XYZ[1] = XYZ2Fix(xyz.Y); |
| 597 | XYZ[2] = XYZ2Fix(xyz.Z); |
| 598 | |
| 599 | } |
| 600 | |
| 601 | |
| 602 | // To convert from Fixed 1.15 point to double |
| 603 | |
| 604 | static |
| 605 | double XYZ2float(WORD v) |
| 606 | { |
| 607 | Fixed32 fix32; |
| 608 | |
| 609 | // From 1.15 to 15.16 |
| 610 | |
| 611 | fix32 = v << 1; |
| 612 | |
| 613 | // From fixed 15.16 to double |
| 614 | |
| 615 | return FIXED_TO_DOUBLE(fix32); |
| 616 | } |
| 617 | |
| 618 | |
| 619 | void LCMSEXPORT cmsXYZEncoded2Float(LPcmsCIEXYZ fXYZ, const WORD XYZ[3]) |
| 620 | { |
| 621 | |
| 622 | fXYZ -> X = XYZ2float(XYZ[0]); |
| 623 | fXYZ -> Y = XYZ2float(XYZ[1]); |
| 624 | fXYZ -> Z = XYZ2float(XYZ[2]); |
| 625 | |
| 626 | } |