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. Oracle designates this 7 * particular file as subject to the "Classpath" exception as provided 8 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * 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 // 32 // Little Color Management System 33 // Copyright (c) 1998-2010 Marti Maria Saguer 34 // 35 // Permission is hereby granted, free of charge, to any person obtaining 36 // a copy of this software and associated documentation files (the "Software"), 37 // to deal in the Software without restriction, including without limitation 38 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 39 // and/or sell copies of the Software, and to permit persons to whom the Software 40 // is furnished to do so, subject to the following conditions: 41 // 42 // The above copyright notice and this permission notice shall be included in 43 // all copies or substantial portions of the Software. 44 // 45 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 46 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 47 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 48 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 49 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 50 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 51 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 52 // 53 //--------------------------------------------------------------------------------- 54 // 55 56 #include "lcms2_internal.h" 57 58 // inter PCS conversions XYZ <-> CIE L* a* b* 59 /* 60 61 62 CIE 15:2004 CIELab is defined as: 63 64 L* = 116*f(Y/Yn) - 16 0 <= L* <= 100 65 a* = 500*[f(X/Xn) - f(Y/Yn)] 66 b* = 200*[f(Y/Yn) - f(Z/Zn)] 67 68 and 69 70 f(t) = t^(1/3) 1 >= t > (24/116)^3 71 (841/108)*t + (16/116) 0 <= t <= (24/116)^3 72 73 74 Reverse transform is: 75 76 X = Xn*[a* / 500 + (L* + 16) / 116] ^ 3 if (X/Xn) > (24/116) 77 = Xn*(a* / 500 + L* / 116) / 7.787 if (X/Xn) <= (24/116) 78 79 80 81 PCS in Lab2 is encoded as: 82 83 8 bit Lab PCS: 84 85 L* 0..100 into a 0..ff byte. 86 a* t + 128 range is -128.0 +127.0 87 b* 88 89 16 bit Lab PCS: 90 91 L* 0..100 into a 0..ff00 word. 92 a* t + 128 range is -128.0 +127.9961 93 b* 94 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 // Conversions 120 void CMSEXPORT cmsXYZ2xyY(cmsCIExyY* Dest, const cmsCIEXYZ* Source) 121 { 122 cmsFloat64Number ISum; 123 124 ISum = 1./(Source -> X + Source -> Y + Source -> Z); 125 126 Dest -> x = (Source -> X) * ISum; 127 Dest -> y = (Source -> Y) * ISum; 128 Dest -> Y = Source -> Y; 129 } 130 131 void CMSEXPORT cmsxyY2XYZ(cmsCIEXYZ* Dest, const cmsCIExyY* Source) 132 { 133 Dest -> X = (Source -> x / Source -> y) * Source -> Y; 134 Dest -> Y = Source -> Y; 135 Dest -> Z = ((1 - Source -> x - Source -> y) / Source -> y) * Source -> Y; 136 } 137 138 static 139 cmsFloat64Number f(cmsFloat64Number t) 140 { 141 const cmsFloat64Number Limit = (24.0/116.0) * (24.0/116.0) * (24.0/116.0); 142 143 if (t <= Limit) 144 return (841.0/108.0) * t + (16.0/116.0); 145 else 146 return pow(t, 1.0/3.0); 147 } 148 149 static 150 cmsFloat64Number f_1(cmsFloat64Number t) 151 { 152 const cmsFloat64Number Limit = (24.0/116.0); 153 154 if (t <= Limit) { 155 return (108.0/841.0) * (t - (16.0/116.0)); 156 } 157 158 return t * t * t; 159 } 160 161 162 // Standard XYZ to Lab. it can handle negative XZY numbers in some cases 163 void CMSEXPORT cmsXYZ2Lab(const cmsCIEXYZ* WhitePoint, cmsCIELab* Lab, const cmsCIEXYZ* xyz) 164 { 165 cmsFloat64Number fx, fy, fz; 166 167 if (WhitePoint == NULL) 168 WhitePoint = cmsD50_XYZ(); 169 170 fx = f(xyz->X / WhitePoint->X); 171 fy = f(xyz->Y / WhitePoint->Y); 172 fz = f(xyz->Z / WhitePoint->Z); 173 174 Lab->L = 116.0*fy - 16.0; 175 Lab->a = 500.0*(fx - fy); 176 Lab->b = 200.0*(fy - fz); 177 } 178 179 180 // Standard XYZ to Lab. It can return negative XYZ in some cases 181 void CMSEXPORT cmsLab2XYZ(const cmsCIEXYZ* WhitePoint, cmsCIEXYZ* xyz, const cmsCIELab* Lab) 182 { 183 cmsFloat64Number x, y, z; 184 185 if (WhitePoint == NULL) 186 WhitePoint = cmsD50_XYZ(); 187 188 y = (Lab-> L + 16.0) / 116.0; 189 x = y + 0.002 * Lab -> a; 190 z = y - 0.005 * Lab -> b; 191 192 xyz -> X = f_1(x) * WhitePoint -> X; 193 xyz -> Y = f_1(y) * WhitePoint -> Y; 194 xyz -> Z = f_1(z) * WhitePoint -> Z; 195 196 } 197 198 static 199 cmsFloat64Number L2float2(cmsUInt16Number v) 200 { 201 return (cmsFloat64Number) v / 652.800; 202 } 203 204 // the a/b part 205 static 206 cmsFloat64Number ab2float2(cmsUInt16Number v) 207 { 208 return ((cmsFloat64Number) v / 256.0) - 128.0; 209 } 210 211 static 212 cmsUInt16Number L2Fix2(cmsFloat64Number L) 213 { 214 return _cmsQuickSaturateWord(L * 652.8); 215 } 216 217 static 218 cmsUInt16Number ab2Fix2(cmsFloat64Number ab) 219 { 220 return _cmsQuickSaturateWord((ab + 128.0) * 256.0); 221 } 222 223 224 static 225 cmsFloat64Number L2float4(cmsUInt16Number v) 226 { 227 return (cmsFloat64Number) v / 655.35; 228 } 229 230 // the a/b part 231 static 232 cmsFloat64Number ab2float4(cmsUInt16Number v) 233 { 234 return ((cmsFloat64Number) v / 257.0) - 128.0; 235 } 236 237 238 void CMSEXPORT cmsLabEncoded2FloatV2(cmsCIELab* Lab, const cmsUInt16Number wLab[3]) 239 { 240 Lab->L = L2float2(wLab[0]); 241 Lab->a = ab2float2(wLab[1]); 242 Lab->b = ab2float2(wLab[2]); 243 } 244 245 246 void CMSEXPORT cmsLabEncoded2Float(cmsCIELab* Lab, const cmsUInt16Number wLab[3]) 247 { 248 Lab->L = L2float4(wLab[0]); 249 Lab->a = ab2float4(wLab[1]); 250 Lab->b = ab2float4(wLab[2]); 251 } 252 253 static 254 cmsFloat64Number Clamp_L_doubleV2(cmsFloat64Number L) 255 { 256 const cmsFloat64Number L_max = (cmsFloat64Number) (0xFFFF * 100.0) / 0xFF00; 257 258 if (L < 0) L = 0; 259 if (L > L_max) L = L_max; 260 261 return L; 262 } 263 264 265 static 266 cmsFloat64Number Clamp_ab_doubleV2(cmsFloat64Number ab) 267 { 268 if (ab < MIN_ENCODEABLE_ab2) ab = MIN_ENCODEABLE_ab2; 269 if (ab > MAX_ENCODEABLE_ab2) ab = MAX_ENCODEABLE_ab2; 270 271 return ab; 272 } 273 274 void CMSEXPORT cmsFloat2LabEncodedV2(cmsUInt16Number wLab[3], const cmsCIELab* fLab) 275 { 276 cmsCIELab Lab; 277 278 Lab.L = Clamp_L_doubleV2(fLab ->L); 279 Lab.a = Clamp_ab_doubleV2(fLab ->a); 280 Lab.b = Clamp_ab_doubleV2(fLab ->b); 281 282 wLab[0] = L2Fix2(Lab.L); 283 wLab[1] = ab2Fix2(Lab.a); 284 wLab[2] = ab2Fix2(Lab.b); 285 } 286 287 288 static 289 cmsFloat64Number Clamp_L_doubleV4(cmsFloat64Number L) 290 { 291 if (L < 0) L = 0; 292 if (L > 100.0) L = 100.0; 293 294 return L; 295 } 296 297 static 298 cmsFloat64Number Clamp_ab_doubleV4(cmsFloat64Number ab) 299 { 300 if (ab < MIN_ENCODEABLE_ab4) ab = MIN_ENCODEABLE_ab4; 301 if (ab > MAX_ENCODEABLE_ab4) ab = MAX_ENCODEABLE_ab4; 302 303 return ab; 304 } 305 306 static 307 cmsUInt16Number L2Fix4(cmsFloat64Number L) 308 { 309 return _cmsQuickSaturateWord(L * 655.35); 310 } 311 312 static 313 cmsUInt16Number ab2Fix4(cmsFloat64Number ab) 314 { 315 return _cmsQuickSaturateWord((ab + 128.0) * 257.0); 316 } 317 318 void CMSEXPORT cmsFloat2LabEncoded(cmsUInt16Number wLab[3], const cmsCIELab* fLab) 319 { 320 cmsCIELab Lab; 321 322 Lab.L = Clamp_L_doubleV4(fLab ->L); 323 Lab.a = Clamp_ab_doubleV4(fLab ->a); 324 Lab.b = Clamp_ab_doubleV4(fLab ->b); 325 326 wLab[0] = L2Fix4(Lab.L); 327 wLab[1] = ab2Fix4(Lab.a); 328 wLab[2] = ab2Fix4(Lab.b); 329 } 330 331 // Auxiliar: convert to Radians 332 static 333 cmsFloat64Number RADIANS(cmsFloat64Number deg) 334 { 335 return (deg * M_PI) / 180.; 336 } 337 338 339 // Auxiliar: atan2 but operating in degrees and returning 0 if a==b==0 340 static 341 cmsFloat64Number atan2deg(cmsFloat64Number a, cmsFloat64Number b) 342 { 343 cmsFloat64Number h; 344 345 if (a == 0 && b == 0) 346 h = 0; 347 else 348 h = atan2(a, b); 349 350 h *= (180. / M_PI); 351 352 while (h > 360.) 353 h -= 360.; 354 355 while ( h < 0) 356 h += 360.; 357 358 return h; 359 } 360 361 362 // Auxiliar: Square 363 static 364 cmsFloat64Number Sqr(cmsFloat64Number v) 365 { 366 return v * v; 367 } 368 // From cylindrical coordinates. No check is performed, then negative values are allowed 369 void CMSEXPORT cmsLab2LCh(cmsCIELCh* LCh, const cmsCIELab* Lab) 370 { 371 LCh -> L = Lab -> L; 372 LCh -> C = pow(Sqr(Lab ->a) + Sqr(Lab ->b), 0.5); 373 LCh -> h = atan2deg(Lab ->b, Lab ->a); 374 } 375 376 377 // To cylindrical coordinates. No check is performed, then negative values are allowed 378 void CMSEXPORT cmsLCh2Lab(cmsCIELab* Lab, const cmsCIELCh* LCh) 379 { 380 cmsFloat64Number h = (LCh -> h * M_PI) / 180.0; 381 382 Lab -> L = LCh -> L; 383 Lab -> a = LCh -> C * cos(h); 384 Lab -> b = LCh -> C * sin(h); 385 } 386 387 // In XYZ All 3 components are encoded using 1.15 fixed point 388 static 389 cmsUInt16Number XYZ2Fix(cmsFloat64Number d) 390 { 391 return _cmsQuickSaturateWord(d * 32768.0); 392 } 393 394 void CMSEXPORT cmsFloat2XYZEncoded(cmsUInt16Number XYZ[3], const cmsCIEXYZ* fXYZ) 395 { 396 cmsCIEXYZ xyz; 397 398 xyz.X = fXYZ -> X; 399 xyz.Y = fXYZ -> Y; 400 xyz.Z = fXYZ -> Z; 401 402 // Clamp to encodeable values. 403 if (xyz.Y <= 0) { 404 405 xyz.X = 0; 406 xyz.Y = 0; 407 xyz.Z = 0; 408 } 409 410 if (xyz.X > MAX_ENCODEABLE_XYZ) 411 xyz.X = MAX_ENCODEABLE_XYZ; 412 413 if (xyz.X < 0) 414 xyz.X = 0; 415 416 if (xyz.Y > MAX_ENCODEABLE_XYZ) 417 xyz.Y = MAX_ENCODEABLE_XYZ; 418 419 if (xyz.Y < 0) 420 xyz.Y = 0; 421 422 if (xyz.Z > MAX_ENCODEABLE_XYZ) 423 xyz.Z = MAX_ENCODEABLE_XYZ; 424 425 if (xyz.Z < 0) 426 xyz.Z = 0; 427 428 429 XYZ[0] = XYZ2Fix(xyz.X); 430 XYZ[1] = XYZ2Fix(xyz.Y); 431 XYZ[2] = XYZ2Fix(xyz.Z); 432 } 433 434 435 // To convert from Fixed 1.15 point to cmsFloat64Number 436 static 437 cmsFloat64Number XYZ2float(cmsUInt16Number v) 438 { 439 cmsS15Fixed16Number fix32; 440 441 // From 1.15 to 15.16 442 fix32 = v << 1; 443 444 // From fixed 15.16 to cmsFloat64Number 445 return _cms15Fixed16toDouble(fix32); 446 } 447 448 449 void CMSEXPORT cmsXYZEncoded2Float(cmsCIEXYZ* fXYZ, const cmsUInt16Number XYZ[3]) 450 { 451 fXYZ -> X = XYZ2float(XYZ[0]); 452 fXYZ -> Y = XYZ2float(XYZ[1]); 453 fXYZ -> Z = XYZ2float(XYZ[2]); 454 } 455 456 457 // Returns dE on two Lab values 458 cmsFloat64Number CMSEXPORT cmsDeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2) 459 { 460 cmsFloat64Number dL, da, db; 461 462 dL = fabs(Lab1 -> L - Lab2 -> L); 463 da = fabs(Lab1 -> a - Lab2 -> a); 464 db = fabs(Lab1 -> b - Lab2 -> b); 465 466 return pow(Sqr(dL) + Sqr(da) + Sqr(db), 0.5); 467 } 468 469 470 // Return the CIE94 Delta E 471 cmsFloat64Number CMSEXPORT cmsCIE94DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2) 472 { 473 cmsCIELCh LCh1, LCh2; 474 cmsFloat64Number dE, dL, dC, dh, dhsq; 475 cmsFloat64Number c12, sc, sh; 476 477 dL = fabs(Lab1 ->L - Lab2 ->L); 478 479 cmsLab2LCh(&LCh1, Lab1); 480 cmsLab2LCh(&LCh2, Lab2); 481 482 dC = fabs(LCh1.C - LCh2.C); 483 dE = cmsDeltaE(Lab1, Lab2); 484 485 dhsq = Sqr(dE) - Sqr(dL) - Sqr(dC); 486 if (dhsq < 0) 487 dh = 0; 488 else 489 dh = pow(dhsq, 0.5); 490 491 c12 = sqrt(LCh1.C * LCh2.C); 492 493 sc = 1.0 + (0.048 * c12); 494 sh = 1.0 + (0.014 * c12); 495 496 return sqrt(Sqr(dL) + Sqr(dC) / Sqr(sc) + Sqr(dh) / Sqr(sh)); 497 } 498 499 500 // Auxiliary 501 static 502 cmsFloat64Number ComputeLBFD(const cmsCIELab* Lab) 503 { 504 cmsFloat64Number yt; 505 506 if (Lab->L > 7.996969) 507 yt = (Sqr((Lab->L+16)/116)*((Lab->L+16)/116))*100; 508 else 509 yt = 100 * (Lab->L / 903.3); 510 511 return (54.6 * (M_LOG10E * (log(yt + 1.5))) - 9.6); 512 } 513 514 515 516 // bfd - gets BFD(1:1) difference between Lab1, Lab2 517 cmsFloat64Number CMSEXPORT cmsBFDdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2) 518 { 519 cmsFloat64Number lbfd1,lbfd2,AveC,Aveh,dE,deltaL, 520 deltaC,deltah,dc,t,g,dh,rh,rc,rt,bfd; 521 cmsCIELCh LCh1, LCh2; 522 523 524 lbfd1 = ComputeLBFD(Lab1); 525 lbfd2 = ComputeLBFD(Lab2); 526 deltaL = lbfd2 - lbfd1; 527 528 cmsLab2LCh(&LCh1, Lab1); 529 cmsLab2LCh(&LCh2, Lab2); 530 531 deltaC = LCh2.C - LCh1.C; 532 AveC = (LCh1.C+LCh2.C)/2; 533 Aveh = (LCh1.h+LCh2.h)/2; 534 535 dE = cmsDeltaE(Lab1, Lab2); 536 537 if (Sqr(dE)>(Sqr(Lab2->L-Lab1->L)+Sqr(deltaC))) 538 deltah = sqrt(Sqr(dE)-Sqr(Lab2->L-Lab1->L)-Sqr(deltaC)); 539 else 540 deltah =0; 541 542 543 dc = 0.035 * AveC / (1 + 0.00365 * AveC)+0.521; 544 g = sqrt(Sqr(Sqr(AveC))/(Sqr(Sqr(AveC))+14000)); 545 t = 0.627+(0.055*cos((Aveh-254)/(180/M_PI))- 546 0.040*cos((2*Aveh-136)/(180/M_PI))+ 547 0.070*cos((3*Aveh-31)/(180/M_PI))+ 548 0.049*cos((4*Aveh+114)/(180/M_PI))- 549 0.015*cos((5*Aveh-103)/(180/M_PI))); 550 551 dh = dc*(g*t+1-g); 552 rh = -0.260*cos((Aveh-308)/(180/M_PI))- 553 0.379*cos((2*Aveh-160)/(180/M_PI))- 554 0.636*cos((3*Aveh+254)/(180/M_PI))+ 555 0.226*cos((4*Aveh+140)/(180/M_PI))- 556 0.194*cos((5*Aveh+280)/(180/M_PI)); 557 558 rc = sqrt((AveC*AveC*AveC*AveC*AveC*AveC)/((AveC*AveC*AveC*AveC*AveC*AveC)+70000000)); 559 rt = rh*rc; 560 561 bfd = sqrt(Sqr(deltaL)+Sqr(deltaC/dc)+Sqr(deltah/dh)+(rt*(deltaC/dc)*(deltah/dh))); 562 563 return bfd; 564 } 565 566 567 // cmc - CMC(l:c) difference between Lab1, Lab2 568 cmsFloat64Number CMSEXPORT cmsCMCdeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, cmsFloat64Number l, cmsFloat64Number c) 569 { 570 cmsFloat64Number dE,dL,dC,dh,sl,sc,sh,t,f,cmc; 571 cmsCIELCh LCh1, LCh2; 572 573 if (Lab1 ->L == 0 && Lab2 ->L == 0) return 0; 574 575 cmsLab2LCh(&LCh1, Lab1); 576 cmsLab2LCh(&LCh2, Lab2); 577 578 579 dL = Lab2->L-Lab1->L; 580 dC = LCh2.C-LCh1.C; 581 582 dE = cmsDeltaE(Lab1, Lab2); 583 584 if (Sqr(dE)>(Sqr(dL)+Sqr(dC))) 585 dh = sqrt(Sqr(dE)-Sqr(dL)-Sqr(dC)); 586 else 587 dh =0; 588 589 if ((LCh1.h > 164) && (LCh1.h < 345)) 590 t = 0.56 + fabs(0.2 * cos(((LCh1.h + 168)/(180/M_PI)))); 591 else 592 t = 0.36 + fabs(0.4 * cos(((LCh1.h + 35 )/(180/M_PI)))); 593 594 sc = 0.0638 * LCh1.C / (1 + 0.0131 * LCh1.C) + 0.638; 595 sl = 0.040975 * Lab1->L /(1 + 0.01765 * Lab1->L); 596 597 if (Lab1->L<16) 598 sl = 0.511; 599 600 f = sqrt((LCh1.C * LCh1.C * LCh1.C * LCh1.C)/((LCh1.C * LCh1.C * LCh1.C * LCh1.C)+1900)); 601 sh = sc*(t*f+1-f); 602 cmc = sqrt(Sqr(dL/(l*sl))+Sqr(dC/(c*sc))+Sqr(dh/sh)); 603 604 return cmc; 605 } 606 607 // dE2000 The weightings KL, KC and KH can be modified to reflect the relative 608 // importance of lightness, chroma and hue in different industrial applications 609 cmsFloat64Number CMSEXPORT cmsCIE2000DeltaE(const cmsCIELab* Lab1, const cmsCIELab* Lab2, 610 cmsFloat64Number Kl, cmsFloat64Number Kc, cmsFloat64Number Kh) 611 { 612 cmsFloat64Number L1 = Lab1->L; 613 cmsFloat64Number a1 = Lab1->a; 614 cmsFloat64Number b1 = Lab1->b; 615 cmsFloat64Number C = sqrt( Sqr(a1) + Sqr(b1) ); 616 617 cmsFloat64Number Ls = Lab2 ->L; 618 cmsFloat64Number as = Lab2 ->a; 619 cmsFloat64Number bs = Lab2 ->b; 620 cmsFloat64Number Cs = sqrt( Sqr(as) + Sqr(bs) ); 621 622 cmsFloat64Number G = 0.5 * ( 1 - sqrt(pow((C + Cs) / 2 , 7.0) / (pow((C + Cs) / 2, 7.0) + pow(25.0, 7.0) ) )); 623 624 cmsFloat64Number a_p = (1 + G ) * a1; 625 cmsFloat64Number b_p = b1; 626 cmsFloat64Number C_p = sqrt( Sqr(a_p) + Sqr(b_p)); 627 cmsFloat64Number h_p = atan2deg(b_p, a_p); 628 629 630 cmsFloat64Number a_ps = (1 + G) * as; 631 cmsFloat64Number b_ps = bs; 632 cmsFloat64Number C_ps = sqrt(Sqr(a_ps) + Sqr(b_ps)); 633 cmsFloat64Number h_ps = atan2deg(b_ps, a_ps); 634 635 cmsFloat64Number meanC_p =(C_p + C_ps) / 2; 636 637 cmsFloat64Number hps_plus_hp = h_ps + h_p; 638 cmsFloat64Number hps_minus_hp = h_ps - h_p; 639 640 cmsFloat64Number meanh_p = fabs(hps_minus_hp) <= 180.000001 ? (hps_plus_hp)/2 : 641 (hps_plus_hp) < 360 ? (hps_plus_hp + 360)/2 : 642 (hps_plus_hp - 360)/2; 643 644 cmsFloat64Number delta_h = (hps_minus_hp) <= -180.000001 ? (hps_minus_hp + 360) : 645 (hps_minus_hp) > 180 ? (hps_minus_hp - 360) : 646 (hps_minus_hp); 647 cmsFloat64Number delta_L = (Ls - L1); 648 cmsFloat64Number delta_C = (C_ps - C_p ); 649 650 651 cmsFloat64Number delta_H =2 * sqrt(C_ps*C_p) * sin(RADIANS(delta_h) / 2); 652 653 cmsFloat64Number T = 1 - 0.17 * cos(RADIANS(meanh_p-30)) 654 + 0.24 * cos(RADIANS(2*meanh_p)) 655 + 0.32 * cos(RADIANS(3*meanh_p + 6)) 656 - 0.2 * cos(RADIANS(4*meanh_p - 63)); 657 658 cmsFloat64Number Sl = 1 + (0.015 * Sqr((Ls + L1) /2- 50) )/ sqrt(20 + Sqr( (Ls+L1)/2 - 50) ); 659 660 cmsFloat64Number Sc = 1 + 0.045 * (C_p + C_ps)/2; 661 cmsFloat64Number Sh = 1 + 0.015 * ((C_ps + C_p)/2) * T; 662 663 cmsFloat64Number delta_ro = 30 * exp( -Sqr(((meanh_p - 275 ) / 25))); 664 665 cmsFloat64Number Rc = 2 * sqrt(( pow(meanC_p, 7.0) )/( pow(meanC_p, 7.0) + pow(25.0, 7.0))); 666 667 cmsFloat64Number Rt = -sin(2 * RADIANS(delta_ro)) * Rc; 668 669 cmsFloat64Number deltaE00 = sqrt( Sqr(delta_L /(Sl * Kl)) + 670 Sqr(delta_C/(Sc * Kc)) + 671 Sqr(delta_H/(Sh * Kh)) + 672 Rt*(delta_C/(Sc * Kc)) * (delta_H / (Sh * Kh))); 673 674 return deltaE00; 675 } 676 677 // This function returns a number of gridpoints to be used as LUT table. It assumes same number 678 // of gripdpoints in all dimensions. Flags may override the choice. 679 int _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags) 680 { 681 int nChannels; 682 683 // Already specified? 684 if (dwFlags & 0x00FF0000) { 685 // Yes, grab'em 686 return (dwFlags >> 16) & 0xFF; 687 } 688 689 nChannels = cmsChannelsOf(Colorspace); 690 691 // HighResPrecalc is maximum resolution 692 if (dwFlags & cmsFLAGS_HIGHRESPRECALC) { 693 694 if (nChannels > 4) 695 return 7; // 7 for Hifi 696 697 if (nChannels == 4) // 23 for CMYK 698 return 23; 699 700 return 49; // 49 for RGB and others 701 } 702 703 704 // LowResPrecal is lower resolution 705 if (dwFlags & cmsFLAGS_LOWRESPRECALC) { 706 707 if (nChannels > 4) 708 return 6; // 6 for more than 4 channels 709 710 if (nChannels == 1) 711 return 33; // For monochrome 712 713 return 17; // 17 for remaining 714 } 715 716 // Default values 717 if (nChannels > 4) 718 return 7; // 7 for Hifi 719 720 if (nChannels == 4) 721 return 17; // 17 for CMYK 722 723 return 33; // 33 for RGB 724 } 725 726 727 cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space, 728 cmsUInt16Number **White, 729 cmsUInt16Number **Black, 730 cmsUInt32Number *nOutputs) 731 { 732 // Only most common spaces 733 734 static cmsUInt16Number RGBblack[4] = { 0, 0, 0 }; 735 static cmsUInt16Number RGBwhite[4] = { 0xffff, 0xffff, 0xffff }; 736 static cmsUInt16Number CMYKblack[4] = { 0xffff, 0xffff, 0xffff, 0xffff }; // 400% of ink 737 static cmsUInt16Number CMYKwhite[4] = { 0, 0, 0, 0 }; 738 static cmsUInt16Number LABblack[4] = { 0, 0x8080, 0x8080 }; // V4 Lab encoding 739 static cmsUInt16Number LABwhite[4] = { 0xFFFF, 0x8080, 0x8080 }; 740 static cmsUInt16Number CMYblack[4] = { 0xffff, 0xffff, 0xffff }; 741 static cmsUInt16Number CMYwhite[4] = { 0, 0, 0 }; 742 static cmsUInt16Number Grayblack[4] = { 0 }; 743 static cmsUInt16Number GrayWhite[4] = { 0xffff }; 744 745 switch (Space) { 746 747 case cmsSigGrayData: if (White) *White = GrayWhite; 748 if (Black) *Black = Grayblack; 749 if (nOutputs) *nOutputs = 1; 750 return TRUE; 751 752 case cmsSigRgbData: if (White) *White = RGBwhite; 753 if (Black) *Black = RGBblack; 754 if (nOutputs) *nOutputs = 3; 755 return TRUE; 756 757 case cmsSigLabData: if (White) *White = LABwhite; 758 if (Black) *Black = LABblack; 759 if (nOutputs) *nOutputs = 3; 760 return TRUE; 761 762 case cmsSigCmykData: if (White) *White = CMYKwhite; 763 if (Black) *Black = CMYKblack; 764 if (nOutputs) *nOutputs = 4; 765 return TRUE; 766 767 case cmsSigCmyData: if (White) *White = CMYwhite; 768 if (Black) *Black = CMYblack; 769 if (nOutputs) *nOutputs = 3; 770 return TRUE; 771 772 default:; 773 } 774 775 return FALSE; 776 } 777 778 779 780 // Several utilities ------------------------------------------------------- 781 782 // Translate from our colorspace to ICC representation 783 784 cmsColorSpaceSignature CMSEXPORT _cmsICCcolorSpace(int OurNotation) 785 { 786 switch (OurNotation) { 787 788 case 1: 789 case PT_GRAY: return cmsSigGrayData; 790 791 case 2: 792 case PT_RGB: return cmsSigRgbData; 793 794 case PT_CMY: return cmsSigCmyData; 795 case PT_CMYK: return cmsSigCmykData; 796 case PT_YCbCr:return cmsSigYCbCrData; 797 case PT_YUV: return cmsSigLuvData; 798 case PT_XYZ: return cmsSigXYZData; 799 800 case PT_LabV2: 801 case PT_Lab: return cmsSigLabData; 802 803 case PT_YUVK: return cmsSigLuvKData; 804 case PT_HSV: return cmsSigHsvData; 805 case PT_HLS: return cmsSigHlsData; 806 case PT_Yxy: return cmsSigYxyData; 807 808 case PT_MCH1: return cmsSigMCH1Data; 809 case PT_MCH2: return cmsSigMCH2Data; 810 case PT_MCH3: return cmsSigMCH3Data; 811 case PT_MCH4: return cmsSigMCH4Data; 812 case PT_MCH5: return cmsSigMCH5Data; 813 case PT_MCH6: return cmsSigMCH6Data; 814 case PT_MCH7: return cmsSigMCH7Data; 815 case PT_MCH8: return cmsSigMCH8Data; 816 817 case PT_MCH9: return cmsSigMCH9Data; 818 case PT_MCH10: return cmsSigMCHAData; 819 case PT_MCH11: return cmsSigMCHBData; 820 case PT_MCH12: return cmsSigMCHCData; 821 case PT_MCH13: return cmsSigMCHDData; 822 case PT_MCH14: return cmsSigMCHEData; 823 case PT_MCH15: return cmsSigMCHFData; 824 825 default: return (cmsColorSpaceSignature) (-1); 826 } 827 } 828 829 830 int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignature ProfileSpace) 831 { 832 switch (ProfileSpace) { 833 834 case cmsSigGrayData: return PT_GRAY; 835 case cmsSigRgbData: return PT_RGB; 836 case cmsSigCmyData: return PT_CMY; 837 case cmsSigCmykData: return PT_CMYK; 838 case cmsSigYCbCrData:return PT_YCbCr; 839 case cmsSigLuvData: return PT_YUV; 840 case cmsSigXYZData: return PT_XYZ; 841 case cmsSigLabData: return PT_Lab; 842 case cmsSigLuvKData: return PT_YUVK; 843 case cmsSigHsvData: return PT_HSV; 844 case cmsSigHlsData: return PT_HLS; 845 case cmsSigYxyData: return PT_Yxy; 846 847 case cmsSig1colorData: 848 case cmsSigMCH1Data: return PT_MCH1; 849 850 case cmsSig2colorData: 851 case cmsSigMCH2Data: return PT_MCH2; 852 853 case cmsSig3colorData: 854 case cmsSigMCH3Data: return PT_MCH3; 855 856 case cmsSig4colorData: 857 case cmsSigMCH4Data: return PT_MCH4; 858 859 case cmsSig5colorData: 860 case cmsSigMCH5Data: return PT_MCH5; 861 862 case cmsSig6colorData: 863 case cmsSigMCH6Data: return PT_MCH6; 864 865 case cmsSigMCH7Data: 866 case cmsSig7colorData:return PT_MCH7; 867 868 case cmsSigMCH8Data: 869 case cmsSig8colorData:return PT_MCH8; 870 871 case cmsSigMCH9Data: 872 case cmsSig9colorData:return PT_MCH9; 873 874 case cmsSigMCHAData: 875 case cmsSig10colorData:return PT_MCH10; 876 877 case cmsSigMCHBData: 878 case cmsSig11colorData:return PT_MCH11; 879 880 case cmsSigMCHCData: 881 case cmsSig12colorData:return PT_MCH12; 882 883 case cmsSigMCHDData: 884 case cmsSig13colorData:return PT_MCH13; 885 886 case cmsSigMCHEData: 887 case cmsSig14colorData:return PT_MCH14; 888 889 case cmsSigMCHFData: 890 case cmsSig15colorData:return PT_MCH15; 891 892 default: return (cmsColorSpaceSignature) (-1); 893 } 894 } 895 896 897 cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace) 898 { 899 switch (ColorSpace) { 900 901 case cmsSig1colorData: 902 case cmsSigGrayData: return 1; 903 904 case cmsSig2colorData: return 2; 905 906 case cmsSigXYZData: 907 case cmsSigLabData: 908 case cmsSigLuvData: 909 case cmsSigYCbCrData: 910 case cmsSigYxyData: 911 case cmsSigRgbData: 912 case cmsSigHsvData: 913 case cmsSigHlsData: 914 case cmsSigCmyData: 915 case cmsSig3colorData: return 3; 916 917 case cmsSigLuvKData: 918 case cmsSigCmykData: 919 case cmsSig4colorData: return 4; 920 921 case cmsSigMCH5Data: 922 case cmsSig5colorData: return 5; 923 924 case cmsSigMCH6Data: 925 case cmsSig6colorData: return 6; 926 927 case cmsSigMCH7Data: 928 case cmsSig7colorData: return 7; 929 930 case cmsSigMCH8Data: 931 case cmsSig8colorData: return 8; 932 933 case cmsSigMCH9Data: 934 case cmsSig9colorData: return 9; 935 936 case cmsSigMCHAData: 937 case cmsSig10colorData: return 10; 938 939 case cmsSigMCHBData: 940 case cmsSig11colorData: return 11; 941 942 case cmsSigMCHCData: 943 case cmsSig12colorData: return 12; 944 945 case cmsSigMCHDData: 946 case cmsSig13colorData: return 13; 947 948 case cmsSigMCHEData: 949 case cmsSig14colorData: return 14; 950 951 case cmsSigMCHFData: 952 case cmsSig15colorData: return 15; 953 954 default: return 3; 955 } 956 }