comparison mupdf-source/thirdparty/lcms2/src/cmspcs.c @ 2:b50eed0cc0ef upstream

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