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