Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/native/liblcms/cmscam02.c
41149 views
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-2020 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
// CIECAM 02 appearance model. Many thanks to Jordi Vilar for the debugging.
59
60
// ---------- Implementation --------------------------------------------
61
62
typedef struct {
63
64
cmsFloat64Number XYZ[3];
65
cmsFloat64Number RGB[3];
66
cmsFloat64Number RGBc[3];
67
cmsFloat64Number RGBp[3];
68
cmsFloat64Number RGBpa[3];
69
cmsFloat64Number a, b, h, e, H, A, J, Q, s, t, C, M;
70
cmsFloat64Number abC[2];
71
cmsFloat64Number abs[2];
72
cmsFloat64Number abM[2];
73
74
} CAM02COLOR;
75
76
typedef struct {
77
78
CAM02COLOR adoptedWhite;
79
cmsFloat64Number LA, Yb;
80
cmsFloat64Number F, c, Nc;
81
cmsUInt32Number surround;
82
cmsFloat64Number n, Nbb, Ncb, z, FL, D;
83
84
cmsContext ContextID;
85
86
} cmsCIECAM02;
87
88
89
static
90
cmsFloat64Number compute_n(cmsCIECAM02* pMod)
91
{
92
return (pMod -> Yb / pMod -> adoptedWhite.XYZ[1]);
93
}
94
95
static
96
cmsFloat64Number compute_z(cmsCIECAM02* pMod)
97
{
98
return (1.48 + pow(pMod -> n, 0.5));
99
}
100
101
static
102
cmsFloat64Number computeNbb(cmsCIECAM02* pMod)
103
{
104
return (0.725 * pow((1.0 / pMod -> n), 0.2));
105
}
106
107
static
108
cmsFloat64Number computeFL(cmsCIECAM02* pMod)
109
{
110
cmsFloat64Number k, FL;
111
112
k = 1.0 / ((5.0 * pMod->LA) + 1.0);
113
FL = 0.2 * pow(k, 4.0) * (5.0 * pMod->LA) + 0.1 *
114
(pow((1.0 - pow(k, 4.0)), 2.0)) *
115
(pow((5.0 * pMod->LA), (1.0 / 3.0)));
116
117
return FL;
118
}
119
120
static
121
cmsFloat64Number computeD(cmsCIECAM02* pMod)
122
{
123
cmsFloat64Number D;
124
125
D = pMod->F - (1.0/3.6)*(exp(((-pMod ->LA-42) / 92.0)));
126
127
return D;
128
}
129
130
131
static
132
CAM02COLOR XYZtoCAT02(CAM02COLOR clr)
133
{
134
clr.RGB[0] = (clr.XYZ[0] * 0.7328) + (clr.XYZ[1] * 0.4296) + (clr.XYZ[2] * -0.1624);
135
clr.RGB[1] = (clr.XYZ[0] * -0.7036) + (clr.XYZ[1] * 1.6975) + (clr.XYZ[2] * 0.0061);
136
clr.RGB[2] = (clr.XYZ[0] * 0.0030) + (clr.XYZ[1] * 0.0136) + (clr.XYZ[2] * 0.9834);
137
138
return clr;
139
}
140
141
static
142
CAM02COLOR ChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod)
143
{
144
cmsUInt32Number i;
145
146
for (i = 0; i < 3; i++) {
147
clr.RGBc[i] = ((pMod -> adoptedWhite.XYZ[1] *
148
(pMod->D / pMod -> adoptedWhite.RGB[i])) +
149
(1.0 - pMod->D)) * clr.RGB[i];
150
}
151
152
return clr;
153
}
154
155
156
static
157
CAM02COLOR CAT02toHPE(CAM02COLOR clr)
158
{
159
cmsFloat64Number M[9];
160
161
M[0] =(( 0.38971 * 1.096124) + (0.68898 * 0.454369) + (-0.07868 * -0.009628));
162
M[1] =(( 0.38971 * -0.278869) + (0.68898 * 0.473533) + (-0.07868 * -0.005698));
163
M[2] =(( 0.38971 * 0.182745) + (0.68898 * 0.072098) + (-0.07868 * 1.015326));
164
M[3] =((-0.22981 * 1.096124) + (1.18340 * 0.454369) + ( 0.04641 * -0.009628));
165
M[4] =((-0.22981 * -0.278869) + (1.18340 * 0.473533) + ( 0.04641 * -0.005698));
166
M[5] =((-0.22981 * 0.182745) + (1.18340 * 0.072098) + ( 0.04641 * 1.015326));
167
M[6] =(-0.009628);
168
M[7] =(-0.005698);
169
M[8] =( 1.015326);
170
171
clr.RGBp[0] = (clr.RGBc[0] * M[0]) + (clr.RGBc[1] * M[1]) + (clr.RGBc[2] * M[2]);
172
clr.RGBp[1] = (clr.RGBc[0] * M[3]) + (clr.RGBc[1] * M[4]) + (clr.RGBc[2] * M[5]);
173
clr.RGBp[2] = (clr.RGBc[0] * M[6]) + (clr.RGBc[1] * M[7]) + (clr.RGBc[2] * M[8]);
174
175
return clr;
176
}
177
178
static
179
CAM02COLOR NonlinearCompression(CAM02COLOR clr, cmsCIECAM02* pMod)
180
{
181
cmsUInt32Number i;
182
cmsFloat64Number temp;
183
184
for (i = 0; i < 3; i++) {
185
if (clr.RGBp[i] < 0) {
186
187
temp = pow((-1.0 * pMod->FL * clr.RGBp[i] / 100.0), 0.42);
188
clr.RGBpa[i] = (-1.0 * 400.0 * temp) / (temp + 27.13) + 0.1;
189
}
190
else {
191
temp = pow((pMod->FL * clr.RGBp[i] / 100.0), 0.42);
192
clr.RGBpa[i] = (400.0 * temp) / (temp + 27.13) + 0.1;
193
}
194
}
195
196
clr.A = (((2.0 * clr.RGBpa[0]) + clr.RGBpa[1] +
197
(clr.RGBpa[2] / 20.0)) - 0.305) * pMod->Nbb;
198
199
return clr;
200
}
201
202
static
203
CAM02COLOR ComputeCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod)
204
{
205
cmsFloat64Number a, b, temp, e, t, r2d, d2r;
206
207
a = clr.RGBpa[0] - (12.0 * clr.RGBpa[1] / 11.0) + (clr.RGBpa[2] / 11.0);
208
b = (clr.RGBpa[0] + clr.RGBpa[1] - (2.0 * clr.RGBpa[2])) / 9.0;
209
210
r2d = (180.0 / 3.141592654);
211
if (a == 0) {
212
if (b == 0) clr.h = 0;
213
else if (b > 0) clr.h = 90;
214
else clr.h = 270;
215
}
216
else if (a > 0) {
217
temp = b / a;
218
if (b > 0) clr.h = (r2d * atan(temp));
219
else if (b == 0) clr.h = 0;
220
else clr.h = (r2d * atan(temp)) + 360;
221
}
222
else {
223
temp = b / a;
224
clr.h = (r2d * atan(temp)) + 180;
225
}
226
227
d2r = (3.141592654 / 180.0);
228
e = ((12500.0 / 13.0) * pMod->Nc * pMod->Ncb) *
229
(cos((clr.h * d2r + 2.0)) + 3.8);
230
231
if (clr.h < 20.14) {
232
temp = ((clr.h + 122.47)/1.2) + ((20.14 - clr.h)/0.8);
233
clr.H = 300 + (100*((clr.h + 122.47)/1.2)) / temp;
234
}
235
else if (clr.h < 90.0) {
236
temp = ((clr.h - 20.14)/0.8) + ((90.00 - clr.h)/0.7);
237
clr.H = (100*((clr.h - 20.14)/0.8)) / temp;
238
}
239
else if (clr.h < 164.25) {
240
temp = ((clr.h - 90.00)/0.7) + ((164.25 - clr.h)/1.0);
241
clr.H = 100 + ((100*((clr.h - 90.00)/0.7)) / temp);
242
}
243
else if (clr.h < 237.53) {
244
temp = ((clr.h - 164.25)/1.0) + ((237.53 - clr.h)/1.2);
245
clr.H = 200 + ((100*((clr.h - 164.25)/1.0)) / temp);
246
}
247
else {
248
temp = ((clr.h - 237.53)/1.2) + ((360 - clr.h + 20.14)/0.8);
249
clr.H = 300 + ((100*((clr.h - 237.53)/1.2)) / temp);
250
}
251
252
clr.J = 100.0 * pow((clr.A / pMod->adoptedWhite.A),
253
(pMod->c * pMod->z));
254
255
clr.Q = (4.0 / pMod->c) * pow((clr.J / 100.0), 0.5) *
256
(pMod->adoptedWhite.A + 4.0) * pow(pMod->FL, 0.25);
257
258
t = (e * pow(((a * a) + (b * b)), 0.5)) /
259
(clr.RGBpa[0] + clr.RGBpa[1] +
260
((21.0 / 20.0) * clr.RGBpa[2]));
261
262
clr.C = pow(t, 0.9) * pow((clr.J / 100.0), 0.5) *
263
pow((1.64 - pow(0.29, pMod->n)), 0.73);
264
265
clr.M = clr.C * pow(pMod->FL, 0.25);
266
clr.s = 100.0 * pow((clr.M / clr.Q), 0.5);
267
268
return clr;
269
}
270
271
272
static
273
CAM02COLOR InverseCorrelates(CAM02COLOR clr, cmsCIECAM02* pMod)
274
{
275
276
cmsFloat64Number t, e, p1, p2, p3, p4, p5, hr, d2r;
277
d2r = 3.141592654 / 180.0;
278
279
t = pow( (clr.C / (pow((clr.J / 100.0), 0.5) *
280
(pow((1.64 - pow(0.29, pMod->n)), 0.73)))),
281
(1.0 / 0.9) );
282
e = ((12500.0 / 13.0) * pMod->Nc * pMod->Ncb) *
283
(cos((clr.h * d2r + 2.0)) + 3.8);
284
285
clr.A = pMod->adoptedWhite.A * pow(
286
(clr.J / 100.0),
287
(1.0 / (pMod->c * pMod->z)));
288
289
p1 = e / t;
290
p2 = (clr.A / pMod->Nbb) + 0.305;
291
p3 = 21.0 / 20.0;
292
293
hr = clr.h * d2r;
294
295
if (fabs(sin(hr)) >= fabs(cos(hr))) {
296
p4 = p1 / sin(hr);
297
clr.b = (p2 * (2.0 + p3) * (460.0 / 1403.0)) /
298
(p4 + (2.0 + p3) * (220.0 / 1403.0) *
299
(cos(hr) / sin(hr)) - (27.0 / 1403.0) +
300
p3 * (6300.0 / 1403.0));
301
clr.a = clr.b * (cos(hr) / sin(hr));
302
}
303
else {
304
p5 = p1 / cos(hr);
305
clr.a = (p2 * (2.0 + p3) * (460.0 / 1403.0)) /
306
(p5 + (2.0 + p3) * (220.0 / 1403.0) -
307
((27.0 / 1403.0) - p3 * (6300.0 / 1403.0)) *
308
(sin(hr) / cos(hr)));
309
clr.b = clr.a * (sin(hr) / cos(hr));
310
}
311
312
clr.RGBpa[0] = ((460.0 / 1403.0) * p2) +
313
((451.0 / 1403.0) * clr.a) +
314
((288.0 / 1403.0) * clr.b);
315
clr.RGBpa[1] = ((460.0 / 1403.0) * p2) -
316
((891.0 / 1403.0) * clr.a) -
317
((261.0 / 1403.0) * clr.b);
318
clr.RGBpa[2] = ((460.0 / 1403.0) * p2) -
319
((220.0 / 1403.0) * clr.a) -
320
((6300.0 / 1403.0) * clr.b);
321
322
return clr;
323
}
324
325
static
326
CAM02COLOR InverseNonlinearity(CAM02COLOR clr, cmsCIECAM02* pMod)
327
{
328
cmsUInt32Number i;
329
cmsFloat64Number c1;
330
331
for (i = 0; i < 3; i++) {
332
if ((clr.RGBpa[i] - 0.1) < 0) c1 = -1;
333
else c1 = 1;
334
clr.RGBp[i] = c1 * (100.0 / pMod->FL) *
335
pow(((27.13 * fabs(clr.RGBpa[i] - 0.1)) /
336
(400.0 - fabs(clr.RGBpa[i] - 0.1))),
337
(1.0 / 0.42));
338
}
339
340
return clr;
341
}
342
343
static
344
CAM02COLOR HPEtoCAT02(CAM02COLOR clr)
345
{
346
cmsFloat64Number M[9];
347
348
M[0] = (( 0.7328 * 1.910197) + (0.4296 * 0.370950));
349
M[1] = (( 0.7328 * -1.112124) + (0.4296 * 0.629054));
350
M[2] = (( 0.7328 * 0.201908) + (0.4296 * 0.000008) - 0.1624);
351
M[3] = ((-0.7036 * 1.910197) + (1.6975 * 0.370950));
352
M[4] = ((-0.7036 * -1.112124) + (1.6975 * 0.629054));
353
M[5] = ((-0.7036 * 0.201908) + (1.6975 * 0.000008) + 0.0061);
354
M[6] = (( 0.0030 * 1.910197) + (0.0136 * 0.370950));
355
M[7] = (( 0.0030 * -1.112124) + (0.0136 * 0.629054));
356
M[8] = (( 0.0030 * 0.201908) + (0.0136 * 0.000008) + 0.9834);;
357
358
clr.RGBc[0] = (clr.RGBp[0] * M[0]) + (clr.RGBp[1] * M[1]) + (clr.RGBp[2] * M[2]);
359
clr.RGBc[1] = (clr.RGBp[0] * M[3]) + (clr.RGBp[1] * M[4]) + (clr.RGBp[2] * M[5]);
360
clr.RGBc[2] = (clr.RGBp[0] * M[6]) + (clr.RGBp[1] * M[7]) + (clr.RGBp[2] * M[8]);
361
return clr;
362
}
363
364
365
static
366
CAM02COLOR InverseChromaticAdaptation(CAM02COLOR clr, cmsCIECAM02* pMod)
367
{
368
cmsUInt32Number i;
369
for (i = 0; i < 3; i++) {
370
clr.RGB[i] = clr.RGBc[i] /
371
((pMod->adoptedWhite.XYZ[1] * pMod->D / pMod->adoptedWhite.RGB[i]) + 1.0 - pMod->D);
372
}
373
return clr;
374
}
375
376
377
static
378
CAM02COLOR CAT02toXYZ(CAM02COLOR clr)
379
{
380
clr.XYZ[0] = (clr.RGB[0] * 1.096124) + (clr.RGB[1] * -0.278869) + (clr.RGB[2] * 0.182745);
381
clr.XYZ[1] = (clr.RGB[0] * 0.454369) + (clr.RGB[1] * 0.473533) + (clr.RGB[2] * 0.072098);
382
clr.XYZ[2] = (clr.RGB[0] * -0.009628) + (clr.RGB[1] * -0.005698) + (clr.RGB[2] * 1.015326);
383
384
return clr;
385
}
386
387
388
cmsHANDLE CMSEXPORT cmsCIECAM02Init(cmsContext ContextID, const cmsViewingConditions* pVC)
389
{
390
cmsCIECAM02* lpMod;
391
392
_cmsAssert(pVC != NULL);
393
394
if((lpMod = (cmsCIECAM02*) _cmsMallocZero(ContextID, sizeof(cmsCIECAM02))) == NULL) {
395
return NULL;
396
}
397
398
lpMod ->ContextID = ContextID;
399
400
lpMod ->adoptedWhite.XYZ[0] = pVC ->whitePoint.X;
401
lpMod ->adoptedWhite.XYZ[1] = pVC ->whitePoint.Y;
402
lpMod ->adoptedWhite.XYZ[2] = pVC ->whitePoint.Z;
403
404
lpMod -> LA = pVC ->La;
405
lpMod -> Yb = pVC ->Yb;
406
lpMod -> D = pVC ->D_value;
407
lpMod -> surround = pVC ->surround;
408
409
switch (lpMod -> surround) {
410
411
412
case CUTSHEET_SURROUND:
413
lpMod->F = 0.8;
414
lpMod->c = 0.41;
415
lpMod->Nc = 0.8;
416
break;
417
418
case DARK_SURROUND:
419
lpMod -> F = 0.8;
420
lpMod -> c = 0.525;
421
lpMod -> Nc = 0.8;
422
break;
423
424
case DIM_SURROUND:
425
lpMod -> F = 0.9;
426
lpMod -> c = 0.59;
427
lpMod -> Nc = 0.95;
428
break;
429
430
default:
431
// Average surround
432
lpMod -> F = 1.0;
433
lpMod -> c = 0.69;
434
lpMod -> Nc = 1.0;
435
}
436
437
lpMod -> n = compute_n(lpMod);
438
lpMod -> z = compute_z(lpMod);
439
lpMod -> Nbb = computeNbb(lpMod);
440
lpMod -> FL = computeFL(lpMod);
441
442
if (lpMod -> D == D_CALCULATE) {
443
lpMod -> D = computeD(lpMod);
444
}
445
446
lpMod -> Ncb = lpMod -> Nbb;
447
448
lpMod -> adoptedWhite = XYZtoCAT02(lpMod -> adoptedWhite);
449
lpMod -> adoptedWhite = ChromaticAdaptation(lpMod -> adoptedWhite, lpMod);
450
lpMod -> adoptedWhite = CAT02toHPE(lpMod -> adoptedWhite);
451
lpMod -> adoptedWhite = NonlinearCompression(lpMod -> adoptedWhite, lpMod);
452
453
return (cmsHANDLE) lpMod;
454
455
}
456
457
void CMSEXPORT cmsCIECAM02Done(cmsHANDLE hModel)
458
{
459
cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
460
461
if (lpMod) _cmsFree(lpMod ->ContextID, lpMod);
462
}
463
464
465
void CMSEXPORT cmsCIECAM02Forward(cmsHANDLE hModel, const cmsCIEXYZ* pIn, cmsJCh* pOut)
466
{
467
CAM02COLOR clr;
468
cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
469
470
_cmsAssert(lpMod != NULL);
471
_cmsAssert(pIn != NULL);
472
_cmsAssert(pOut != NULL);
473
474
memset(&clr, 0, sizeof(clr));
475
476
clr.XYZ[0] = pIn ->X;
477
clr.XYZ[1] = pIn ->Y;
478
clr.XYZ[2] = pIn ->Z;
479
480
clr = XYZtoCAT02(clr);
481
clr = ChromaticAdaptation(clr, lpMod);
482
clr = CAT02toHPE(clr);
483
clr = NonlinearCompression(clr, lpMod);
484
clr = ComputeCorrelates(clr, lpMod);
485
486
pOut ->J = clr.J;
487
pOut ->C = clr.C;
488
pOut ->h = clr.h;
489
}
490
491
void CMSEXPORT cmsCIECAM02Reverse(cmsHANDLE hModel, const cmsJCh* pIn, cmsCIEXYZ* pOut)
492
{
493
CAM02COLOR clr;
494
cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
495
496
_cmsAssert(lpMod != NULL);
497
_cmsAssert(pIn != NULL);
498
_cmsAssert(pOut != NULL);
499
500
memset(&clr, 0, sizeof(clr));
501
502
clr.J = pIn -> J;
503
clr.C = pIn -> C;
504
clr.h = pIn -> h;
505
506
clr = InverseCorrelates(clr, lpMod);
507
clr = InverseNonlinearity(clr, lpMod);
508
clr = HPEtoCAT02(clr);
509
clr = InverseChromaticAdaptation(clr, lpMod);
510
clr = CAT02toXYZ(clr);
511
512
pOut ->X = clr.XYZ[0];
513
pOut ->Y = clr.XYZ[1];
514
pOut ->Z = clr.XYZ[2];
515
}
516
517