1 |
greg |
1.1 |
#ifndef lint |
2 |
greg |
2.30 |
static const char RCSid[] = "$Id: spec_rgb.c,v 2.29 2023/11/21 01:30:20 greg Exp $"; |
3 |
greg |
1.1 |
#endif |
4 |
|
|
/* |
5 |
|
|
* Convert colors and spectral ranges. |
6 |
greg |
2.11 |
* Added von Kries white-balance calculations 10/01 (GW). |
7 |
|
|
* |
8 |
|
|
* Externals declared in color.h |
9 |
|
|
*/ |
10 |
|
|
|
11 |
greg |
2.12 |
#include "copyright.h" |
12 |
greg |
1.1 |
|
13 |
greg |
2.13 |
#include <stdio.h> |
14 |
|
|
#include <string.h> |
15 |
greg |
1.1 |
#include "color.h" |
16 |
greg |
2.11 |
|
17 |
|
|
#define CEPS 1e-4 /* color epsilon */ |
18 |
|
|
|
19 |
greg |
2.26 |
#define CEQ(v1,v2) (((v1) <= (v2)+CEPS) & ((v2) <= (v1)+CEPS)) |
20 |
greg |
1.1 |
|
21 |
greg |
2.26 |
#define XYEQ(c1,c2) (CEQ((c1)[CIEX],(c2)[CIEX]) & CEQ((c1)[CIEY],(c2)[CIEY])) |
22 |
greg |
2.5 |
|
23 |
gwlarson |
2.10 |
|
24 |
greg |
2.11 |
RGBPRIMS stdprims = STDPRIMS; /* standard primary chromaticities */ |
25 |
greg |
2.27 |
RGBPRIMS xyzprims = {1,0, 0,1, 0,0, 1.f/3.f,1.f/3.f}; |
26 |
greg |
2.5 |
|
27 |
greg |
2.8 |
COLOR cblack = BLKCOLOR; /* global black color */ |
28 |
|
|
COLOR cwhite = WHTCOLOR; /* global white color */ |
29 |
|
|
|
30 |
greg |
2.11 |
float xyneu[2] = {1./3., 1./3.}; /* neutral xy chromaticities */ |
31 |
|
|
|
32 |
greg |
1.1 |
/* |
33 |
greg |
2.27 |
* The tables below encode the CIE 1931 2° standard observer |
34 |
|
|
* functions for X, Y, and Z. These tables are cumulative, as are |
35 |
|
|
* ones that follow. |
36 |
greg |
1.1 |
*/ |
37 |
|
|
|
38 |
greg |
2.27 |
#define CIE_X_WLMIN 362 |
39 |
|
|
#define CIE_X_WLMAX 774 |
40 |
|
|
|
41 |
|
|
static const unsigned short cie_x_cumul[CIE_X_WLMAX-CIE_X_WLMIN+1] = { |
42 |
|
|
0,1,1,1,1,1,1,2,2,2,3,3,3,4,5,5,6,7,8,9,10,11,12,14,16,18,20,23,26,29, |
43 |
|
|
33,37,41,47,53,60,68,77,86,97,108,121,135,151,170,190,214,241,271,304, |
44 |
|
|
342,385,432,486,545,612,686,768,860,961,1073,1195,1326,1467,1618, |
45 |
|
|
1776,1943,2117,2298,2485,2677,2875,3076,3281,3489,3700,3912,4125,4340,4555, |
46 |
|
|
4769,4983,5197,5409,5620,5830,6038,6244,6448,6651,6851,7049,7245,7437, |
47 |
|
|
7627,7813,7995,8173,8347,8517,8682,8842,8996,9143,9284,9418,9545,9665, |
48 |
|
|
9778,9884,9984,10077,10164,10245,10321,10390,10454,10513,10566,10615, |
49 |
|
|
10659,10698,10734,10766,10794,10819,10842,10861,10879,10893,10906,10917, |
50 |
|
|
10926,10933,10939,10944,10948,10951,10953,10955,10957,10958,10960,10961, |
51 |
|
|
10964,10967,10971,10977,10984,10994,11006,11020,11038,11060,11085,11114, |
52 |
|
|
11148,11187,11231,11280,11335,11396,11464,11537,11618,11705,11799,11901, |
53 |
|
|
12010,12126,12249,12380,12518,12664,12818,12980,13150,13328,13515,13709, |
54 |
|
|
13913,14124,14345,14574,14813,15060,15317,15582,15858,16142,16437,16741, |
55 |
|
|
17055,17379,17713,18057,18412,18776,19151,19536,19931,20337,20753,21180, |
56 |
|
|
21616,22063,22520,22988,23465,23953,24450,24957,25474,26000,26535,27080, |
57 |
|
|
27633,28195,28765,29343,29929,30522,31122,31729,32342,32961,33585,34215, |
58 |
|
|
34849,35487,36129,36775,37423,38073,38724,39375,40027,40679,41329,41978, |
59 |
|
|
42625,43270,43911,44548,45181,45808,46429,47044,47652,48253,48845,49430, |
60 |
|
|
50005,50571,51128,51674,52209,52733,53245,53745,54232,54706,55167,55614, |
61 |
|
|
56048,56468,56876,57269,57651,58019,58376,58720,59052,59373,59681,59979, |
62 |
|
|
60265,60539,60803,61056,61298,61529,61750,61962,62163,62355,62538,62712, |
63 |
|
|
62877,63034,63183,63325,63459,63586,63706,63820,63927,64028,64123,64213, |
64 |
|
|
64297,64376,64451,64520,64586,64647,64704,64758,64808,64855,64899,64941, |
65 |
|
|
64980,65016,65051,65083,65114,65143,65169,65194,65218,65240,65260,65278, |
66 |
|
|
65296,65312,65327,65341,65354,65366,65377,65387,65397,65406,65415,65423, |
67 |
|
|
65430,65437,65444,65450,65455,65461,65466,65470,65475,65479,65483,65486, |
68 |
|
|
65489,65493,65495,65498,65501,65503,65505,65507,65509,65511,65513,65514, |
69 |
|
|
65516,65517,65518,65519,65520,65521,65522,65523,65524,65525,65526,65526, |
70 |
|
|
65527,65527,65528,65528,65529,65529,65530,65530,65530,65531,65531,65531, |
71 |
|
|
65532,65532,65532,65532,65532,65533,65533,65533,65533,65533,65533,65533, |
72 |
|
|
65533,65534,65534,65534,65534,65534,65534,65534,65534,65534,65534,65534, |
73 |
|
|
65534,65534,65534,65534,65535 |
74 |
|
|
}; |
75 |
|
|
|
76 |
|
|
#define CIE_Y_WLMIN 386 |
77 |
|
|
#define CIE_Y_WLMAX 760 |
78 |
|
|
|
79 |
|
|
static const unsigned short cie_y_cumul[CIE_Y_WLMAX-CIE_Y_WLMIN+1] = { |
80 |
|
|
0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,4,4,5,5,6,7,8,8,10,11,12,14, |
81 |
|
|
15,17,19,22,25,28,31,35,40,45,50,56,63,70,78,86,95,105,115,126, |
82 |
|
|
138,150,164,178,193,208,225,242,260,280,300,321,343,367,391, |
83 |
|
|
417,443,472,501,532,564,598,633,670,708,748,790,833,879,926, |
84 |
|
|
975,1027,1080,1136,1194,1255,1318,1384,1453,1525,1601,1679,1761, |
85 |
|
|
1846,1935,2027,2123,2223,2327,2435,2548,2665,2787,2915,3048,3187, |
86 |
|
|
3332,3484,3643,3808,3981,4162,4352,4550,4757,4975,5203,5442,5691, |
87 |
|
|
5952,6225,6509,6805,7114,7435,7769,8116,8476,8849,9235,9634,10045, |
88 |
|
|
10469,10904,11351,11808,12275,12752,13239,13734,14239,14752,15273, |
89 |
|
|
15801,16337,16880,17429,17984,18546,19112,19684,20260,20841,21426, |
90 |
|
|
22015,22608,23203,23802,24403,25007,25612,26220,26828,27439,28050, |
91 |
|
|
28662,29275,29888,30501,31114,31727,32340,32951,33561,34170,34777, |
92 |
|
|
35382,35985,36585,37182,37777,38368,38955,39539,40119,40695,41266, |
93 |
|
|
41832,42393,42950,43501,44046,44586,45119,45646,46167,46682,47189, |
94 |
|
|
47690,48183,48670,49149,49621,50085,50542,50991,51432,51866,52293, |
95 |
|
|
52711,53122,53524,53919,54306,54685,55057,55420,55775,56123,56463, |
96 |
|
|
56795,57119,57435,57743,58044,58337,58623,58901,59172,59435,59691, |
97 |
|
|
59939,60180,60414,60640,60859,61070,61274,61471,61661,61844,62019, |
98 |
|
|
62188,62351,62507,62657,62802,62940,63073,63201,63323,63441,63553, |
99 |
|
|
63660,63763,63861,63954,64043,64128,64208,64285,64358,64427,64493, |
100 |
|
|
64555,64614,64670,64723,64773,64820,64865,64907,64947,64984,65019, |
101 |
|
|
65052,65083,65113,65140,65166,65190,65212,65233,65253,65271,65288, |
102 |
|
|
65304,65319,65334,65347,65360,65371,65383,65393,65403,65412,65420, |
103 |
|
|
65428,65435,65442,65449,65454,65460,65465,65470,65474,65478,65482, |
104 |
|
|
65485,65488,65492,65494,65497,65500,65502,65504,65506,65508,65510, |
105 |
|
|
65512,65513,65515,65516,65517,65519,65520,65521,65522,65523,65523, |
106 |
|
|
65524,65525,65526,65526,65527,65527,65528,65528,65529,65529,65530, |
107 |
|
|
65530,65530,65531,65531,65531,65532,65532,65532,65532,65532,65533, |
108 |
|
|
65533,65533,65533,65533,65533,65533,65534,65534,65534,65534,65534, |
109 |
|
|
65534,65534,65534,65534,65534,65534,65534,65534,65534,65534,65534,65535 |
110 |
|
|
}; |
111 |
|
|
|
112 |
|
|
#define CIE_Z_WLMIN 359 |
113 |
|
|
#define CIE_Z_WLMAX 624 |
114 |
|
|
|
115 |
|
|
static const unsigned short cie_z_cumul[CIE_Z_WLMAX-CIE_Z_WLMIN+1] = { |
116 |
|
|
0,1,1,2,2,3,4,5,6,7,8,9,11,12,14,16,19,22,25,28,32,37,41,47,52,59,66,75,84, |
117 |
|
|
95,107,121,136,154,173,196,221,250,283,321,362,408,458,512,573,640,717,804, |
118 |
|
|
903,1015,1142,1285,1446,1627,1830,2058,2313,2598,2917,3272,3668,4108,4597, |
119 |
|
|
5135,5723,6360,7044,7773,8544,9356,10205,11090,12006,12952,13923,14918, |
120 |
|
|
15934,16967,18016,19076,20148,21227,22312,23401,24492,25585,26678,27771, |
121 |
|
|
28861,29950,31037,32121,33202,34281,35355,36424,37487,38542,39588,40624, |
122 |
|
|
41647,42657,43652,44631,45590,46527,47438,48321,49173,49993,50783,51542, |
123 |
|
|
52270,52968,53636,54275,54885,55465,56018,56543,57042,57514,57961,58384, |
124 |
|
|
58784,59162,59519,59856,60175,60477,60762,61032,61287,61529,61757,61974, |
125 |
|
|
62179,62374,62559,62734,62901,63059,63211,63355,63492,63622,63745,63862, |
126 |
|
|
63971,64075,64172,64263,64347,64427,64500,64569,64632,64692,64747,64798, |
127 |
|
|
64846,64891,64933,64973,65010,65045,65078,65109,65139,65166,65192,65216, |
128 |
|
|
65239,65260,65280,65298,65315,65331,65345,65359,65371,65383,65393,65403, |
129 |
|
|
65412,65420,65428,65435,65441,65447,65452,65457,65462,65466,65470,65473, |
130 |
|
|
65476,65479,65482,65485,65487,65489,65491,65493,65495,65497,65498,65500, |
131 |
|
|
65501,65503,65504,65505,65506,65508,65509,65510,65511,65512,65513,65514, |
132 |
|
|
65515,65516,65517,65518,65519,65520,65520,65521,65522,65523,65523,65524, |
133 |
|
|
65525,65525,65526,65527,65527,65528,65528,65529,65529,65530,65530,65531, |
134 |
|
|
65531,65531,65532,65532,65532,65532,65533,65533,65533,65533,65533,65533, |
135 |
|
|
65534,65534,65534,65534,65534,65534,65534,65534,65534,65535 |
136 |
|
|
}; |
137 |
|
|
|
138 |
|
|
#define SCOTOPIC_WLMIN 382 |
139 |
|
|
#define SCOTOPIC_WLMAX 684 |
140 |
|
|
|
141 |
|
|
static const unsigned short scotopic_cumul[SCOTOPIC_WLMAX-SCOTOPIC_WLMIN+1] = { |
142 |
|
|
0, 1, 1, 2, 3, 4, 5, 6, 7, 9, 10, 12, 15, 17, 20, 24, 28, 33, 38, 44, |
143 |
|
|
52, 60, 69, 80, 93, 107, 123, 142, 163, 186, 213, 242, 275, 312, 353, |
144 |
|
|
398, 448, 502, 562, 627, 698, 775, 859, 949, 1046, 1150, 1261, 1380, |
145 |
|
|
1507, 1642, 1785, 1936, 2096, 2265, 2442, 2628, 2823, 3027, 3239, 3461, |
146 |
|
|
3691, 3930, 4178, 4435, 4700, 4974, 5257, 5548, 5847, 6154, 6469, 6793, |
147 |
|
|
7123, 7462, 7809, 8162, 8524, 8892, 9268, 9651, 10041, 10438, 10843, 11254, |
148 |
|
|
11673, 12099, 12532, 12973, 13422, 13878, 14342, 14814, 15293, 15780, 16276, |
149 |
|
|
16779, 17290, 17809, 18336, 18872, 19415, 19967, 20526, 21093, 21667, 22249, |
150 |
|
|
22839, 23436, 24039, 24649, 25266, 25890, 26519, 27154, 27795, 28441, 29092, |
151 |
|
|
29747, 30405, 31068, 31734, 32402, 33074, 33747, 34420, 35095, 35771, 36446, |
152 |
|
|
37119, 37793, 38464, 39132, 39798, 40460, 41118, 41772, 42421, 43064, 43701, |
153 |
|
|
44332, 44957, 45575, 46185, 46787, 47381, 47967, 48543, 49110, 49668, 50215, |
154 |
|
|
50753, 51280, 51797, 52302, 52797, 53281, 53754, 54215, 54665, 55104, 55531, |
155 |
|
|
55947, 56352, 56744, 57125, 57495, 57853, 58200, 58536, 58860, 59174, 59477, |
156 |
|
|
59769, 60051, 60322, 60583, 60834, 61075, 61306, 61528, 61741, 61944, 62139, |
157 |
|
|
62326, 62504, 62674, 62836, 62991, 63138, 63278, 63412, 63538, 63659, 63773, |
158 |
|
|
63881, 63983, 64080, 64172, 64259, 64340, 64418, 64490, 64559, 64623, 64684, |
159 |
|
|
64742, 64795, 64846, 64893, 64937, 64978, 65017, 65053, 65087, 65119, 65149, |
160 |
|
|
65176, 65202, 65226, 65248, 65269, 65289, 65307, 65323, 65339, 65353, 65367, |
161 |
|
|
65379, 65391, 65402, 65412, 65421, 65430, 65438, 65445, 65452, 65458, 65464, |
162 |
|
|
65469, 65474, 65479, 65483, 65487, 65491, 65494, 65497, 65500, 65503, 65505, |
163 |
|
|
65507, 65509, 65511, 65513, 65514, 65516, 65517, 65519, 65520, 65521, 65522, |
164 |
|
|
65523, 65524, 65525, 65525, 65526, 65527, 65527, 65528, 65528, 65529, 65529, |
165 |
|
|
65529, 65530, 65530, 65530, 65531, 65531, 65531, 65531, 65532, 65532, 65532, |
166 |
|
|
65532, 65532, 65533, 65533, 65533, 65533, 65533, 65533, 65533, 65533, 65533, |
167 |
|
|
65533, 65534, 65534, 65534, 65534, 65534, 65534, 65534, 65534, 65535 |
168 |
|
|
}; |
169 |
|
|
|
170 |
|
|
#define MELANOPIC_WLMIN 380 |
171 |
|
|
#define MELANOPIC_WLMAX 651 |
172 |
|
|
|
173 |
|
|
static const unsigned short melanopic_cumul[MELANOPIC_WLMAX-MELANOPIC_WLMIN+1] = { |
174 |
|
|
0, 1, 2, 3, 4, 5, 7, 8, 10, 12, 14, 17, 20, 23, 27, 32, 37, 42, 49, 56, |
175 |
|
|
65, 75, 86, 99, 114, 131, 150, 173, 200, 230, 265, 303, 347, 395, 448, |
176 |
|
|
508, 574, 650, 734, 828, 931, 1041, 1158, 1283, 1415, 1554, 1703, 1862, |
177 |
|
|
2031, 2211, 2400, 2600, 2809, 3028, 3257, 3497, 3748, 4012, 4288, 4576, |
178 |
|
|
4876, 5187, 5509, 5842, 6185, 6540, 6905, 7283, 7673, 8075, 8489, 8915, |
179 |
|
|
9351, 9799, 10259, 10729, 11211, 11705, 12211, 12729, 13258, 13799, |
180 |
|
|
14351, 14915, 15491, 16078, 16676, 17286, 17908, 18541, 19184, 19837, |
181 |
|
|
20498, 21168, 21846, 22532, 23226, 23928, 24637, 25353, 26075, 26802, |
182 |
|
|
27532, 28267, 29005, 29746, 30488, 31233, 31979, 32726, 33473, 34220, |
183 |
|
|
34966, 35711, 36455, 37196, 37935, 38671, 39403, 40129, 40851, 41568, |
184 |
|
|
42279, 42983, 43680, 44369, 45050, 45724, 46388, 47043, 47688, 48322, |
185 |
|
|
48945, 49557, 50156, 50743, 51317, 51879, 52428, 52964, 53487, 53997, |
186 |
|
|
54493, 54976, 55445, 55901, 56343, 56771, 57186, 57587, 57976, 58351, |
187 |
|
|
58712, 59061, 59397, 59720, 60031, 60330, 60616, 60891, 61154, 61405, |
188 |
|
|
61646, 61875, 62094, 62303, 62501, 62690, 62870, 63040, 63201, 63354, |
189 |
|
|
63498, 63634, 63763, 63884, 63998, 64105, 64206, 64300, 64389, 64472, |
190 |
|
|
64549, 64622, 64689, 64753, 64811, 64866, 64917, 64964, 65008, 65049, |
191 |
|
|
65086, 65121, 65154, 65184, 65211, 65237, 65260, 65282, 65302, 65321, |
192 |
|
|
65338, 65354, 65368, 65381, 65394, 65405, 65415, 65425, 65434, 65442, |
193 |
|
|
65449, 65456, 65463, 65468, 65474, 65479, 65483, 65487, 65491, 65494, |
194 |
|
|
65498, 65501, 65503, 65506, 65508, 65510, 65512, 65514, 65515, 65517, |
195 |
|
|
65518, 65520, 65521, 65522, 65523, 65524, 65525, 65525, 65526, 65527, |
196 |
|
|
65527, 65528, 65528, 65529, 65529, 65530, 65530, 65530, 65531, 65531, |
197 |
|
|
65531, 65531, 65532, 65532, 65532, 65532, 65532, 65533, 65533, 65533, |
198 |
|
|
65533, 65533, 65533, 65533, 65533, 65533, 65534, 65534, 65534, 65535 |
199 |
greg |
1.1 |
}; |
200 |
|
|
|
201 |
greg |
2.11 |
COLORMAT xyz2rgbmat = { /* XYZ to RGB (no white balance) */ |
202 |
greg |
2.3 |
{(CIE_y_g - CIE_y_b - CIE_x_b*CIE_y_g + CIE_y_b*CIE_x_g)/CIE_C_rD, |
203 |
|
|
(CIE_x_b - CIE_x_g - CIE_x_b*CIE_y_g + CIE_x_g*CIE_y_b)/CIE_C_rD, |
204 |
|
|
(CIE_x_g*CIE_y_b - CIE_x_b*CIE_y_g)/CIE_C_rD}, |
205 |
|
|
{(CIE_y_b - CIE_y_r - CIE_y_b*CIE_x_r + CIE_y_r*CIE_x_b)/CIE_C_gD, |
206 |
|
|
(CIE_x_r - CIE_x_b - CIE_x_r*CIE_y_b + CIE_x_b*CIE_y_r)/CIE_C_gD, |
207 |
|
|
(CIE_x_b*CIE_y_r - CIE_x_r*CIE_y_b)/CIE_C_gD}, |
208 |
|
|
{(CIE_y_r - CIE_y_g - CIE_y_r*CIE_x_g + CIE_y_g*CIE_x_r)/CIE_C_bD, |
209 |
|
|
(CIE_x_g - CIE_x_r - CIE_x_g*CIE_y_r + CIE_x_r*CIE_y_g)/CIE_C_bD, |
210 |
|
|
(CIE_x_r*CIE_y_g - CIE_x_g*CIE_y_r)/CIE_C_bD} |
211 |
greg |
1.2 |
}; |
212 |
greg |
1.1 |
|
213 |
greg |
2.11 |
COLORMAT rgb2xyzmat = { /* RGB to XYZ (no white balance) */ |
214 |
greg |
2.4 |
{CIE_x_r*CIE_C_rD/CIE_D,CIE_x_g*CIE_C_gD/CIE_D,CIE_x_b*CIE_C_bD/CIE_D}, |
215 |
|
|
{CIE_y_r*CIE_C_rD/CIE_D,CIE_y_g*CIE_C_gD/CIE_D,CIE_y_b*CIE_C_bD/CIE_D}, |
216 |
|
|
{(1.-CIE_x_r-CIE_y_r)*CIE_C_rD/CIE_D, |
217 |
|
|
(1.-CIE_x_g-CIE_y_g)*CIE_C_gD/CIE_D, |
218 |
|
|
(1.-CIE_x_b-CIE_y_b)*CIE_C_bD/CIE_D} |
219 |
|
|
}; |
220 |
greg |
1.2 |
|
221 |
greg |
2.11 |
COLORMAT vkmat = { /* Sharp primary matrix */ |
222 |
|
|
{ 1.2694, -0.0988, -0.1706}, |
223 |
|
|
{-0.8364, 1.8006, 0.0357}, |
224 |
|
|
{ 0.0297, -0.0315, 1.0018} |
225 |
|
|
}; |
226 |
|
|
|
227 |
|
|
COLORMAT ivkmat = { /* inverse Sharp primary matrix */ |
228 |
|
|
{ 0.8156, 0.0472, 0.1372}, |
229 |
|
|
{ 0.3791, 0.5769, 0.0440}, |
230 |
|
|
{-0.0123, 0.0167, 0.9955} |
231 |
|
|
}; |
232 |
greg |
1.2 |
|
233 |
greg |
2.4 |
|
234 |
greg |
2.11 |
void |
235 |
greg |
2.27 |
spec_cie( /* compute XYZ color from a spectral range */ |
236 |
|
|
COLOR col, /* returned color */ |
237 |
|
|
int s, /* starting and ending wavelengths */ |
238 |
|
|
int e |
239 |
|
|
) |
240 |
|
|
{ |
241 |
|
|
if (s > e) { int i = s; s = e; e = i; } |
242 |
|
|
|
243 |
|
|
if ((s >= CIE_X_WLMAX) | (e <= CIE_X_WLMIN)) |
244 |
|
|
col[CIEX] = 0; |
245 |
|
|
else |
246 |
|
|
col[CIEX] = (cie_x_cumul[e>=CIE_X_WLMAX ? CIE_X_WLMAX-CIE_X_WLMIN : e-CIE_X_WLMIN] - |
247 |
|
|
cie_x_cumul[(s>CIE_X_WLMIN)*(s-CIE_X_WLMIN)])*(1./65535.); |
248 |
|
|
|
249 |
|
|
if ((s >= CIE_Y_WLMAX) | (e <= CIE_Y_WLMIN)) |
250 |
|
|
col[CIEY] = 0; |
251 |
|
|
else |
252 |
|
|
col[CIEY] = (cie_y_cumul[e>=CIE_Y_WLMAX ? CIE_Y_WLMAX-CIE_Y_WLMIN : e-CIE_Y_WLMIN] - |
253 |
|
|
cie_y_cumul[(s>CIE_Y_WLMIN)*(s-CIE_Y_WLMIN)])*(1./65535.); |
254 |
|
|
|
255 |
|
|
if ((s >= CIE_Z_WLMAX) | (e <= CIE_Z_WLMIN)) |
256 |
|
|
col[CIEZ] = 0; |
257 |
|
|
else |
258 |
|
|
col[CIEZ] = (cie_z_cumul[e>=CIE_Z_WLMAX ? CIE_Z_WLMAX-CIE_Z_WLMIN : e-CIE_Z_WLMIN] - |
259 |
|
|
cie_z_cumul[(s>CIE_Z_WLMIN)*(s-CIE_Z_WLMIN)])*(1./65535.); |
260 |
|
|
} |
261 |
|
|
|
262 |
|
|
|
263 |
|
|
void |
264 |
greg |
2.15 |
spec_rgb( /* compute RGB color from spectral range */ |
265 |
|
|
COLOR col, |
266 |
|
|
int s, |
267 |
|
|
int e |
268 |
|
|
) |
269 |
greg |
1.1 |
{ |
270 |
|
|
COLOR ciecolor; |
271 |
|
|
|
272 |
|
|
spec_cie(ciecolor, s, e); |
273 |
|
|
cie_rgb(col, ciecolor); |
274 |
|
|
} |
275 |
|
|
|
276 |
|
|
|
277 |
greg |
2.27 |
static double |
278 |
|
|
spec_dot( /* spectrum dot-product with cumulative observer */ |
279 |
|
|
SCOLOR scol, |
280 |
|
|
int ncs, |
281 |
greg |
2.29 |
const float wlpt[4], |
282 |
greg |
2.27 |
const unsigned short cumul[], |
283 |
|
|
int wlmin, |
284 |
|
|
int wlmax |
285 |
|
|
) |
286 |
|
|
{ |
287 |
|
|
const double wlstp = (wlpt[0] - wlpt[3])/(double)ncs; |
288 |
|
|
int wl1 = (int)wlpt[3]; |
289 |
|
|
int n = 0; |
290 |
|
|
double sum = 0; |
291 |
|
|
|
292 |
|
|
if (wl1 < wlmin) { |
293 |
|
|
n += (int)((wlmin - wl1)/wlstp); |
294 |
|
|
wl1 = wlmin; |
295 |
|
|
} else if (wl1 >= wlmax) |
296 |
|
|
return(.0); |
297 |
|
|
|
298 |
|
|
while (n < ncs) { |
299 |
|
|
int wl0 = wl1; |
300 |
greg |
2.28 |
wl1 = (int)(ncs==3 ? wlpt[2-n] : wlpt[3] + (n+1)*wlstp); |
301 |
greg |
2.27 |
if (wl1 >= wlmax) { |
302 |
greg |
2.28 |
sum += (65535 - cumul[wl0-wlmin]) * scol[ncs-1-n]; |
303 |
greg |
2.27 |
break; |
304 |
|
|
} |
305 |
greg |
2.28 |
sum += (cumul[wl1-wlmin] - cumul[wl0-wlmin]) * scol[ncs-1-n++]; |
306 |
greg |
2.27 |
} |
307 |
|
|
return(sum * (1./65535.)); |
308 |
|
|
} |
309 |
|
|
|
310 |
|
|
|
311 |
greg |
2.11 |
void |
312 |
greg |
2.27 |
scolor2cie( /* accurate conversion from spectrum to XYZ */ |
313 |
|
|
COLOR col, |
314 |
|
|
SCOLOR scol, |
315 |
|
|
int ncs, |
316 |
greg |
2.29 |
const float wlpt[4] |
317 |
greg |
2.27 |
) |
318 |
|
|
{ |
319 |
|
|
if (ncs == 3) { /* not a spectrum! */ |
320 |
|
|
rgb_cie(col, scol); |
321 |
|
|
return; |
322 |
|
|
} |
323 |
|
|
col[CIEX] = spec_dot(scol, ncs, wlpt, cie_x_cumul, CIE_X_WLMIN, CIE_X_WLMAX); |
324 |
|
|
col[CIEY] = spec_dot(scol, ncs, wlpt, cie_y_cumul, CIE_Y_WLMIN, CIE_Y_WLMAX); |
325 |
|
|
col[CIEZ] = spec_dot(scol, ncs, wlpt, cie_z_cumul, CIE_Z_WLMIN, CIE_Z_WLMAX); |
326 |
|
|
} |
327 |
|
|
|
328 |
|
|
|
329 |
|
|
void |
330 |
|
|
scolor2rgb( /* accurate conversion from spectrum to RGB */ |
331 |
|
|
COLOR col, |
332 |
|
|
SCOLOR scol, |
333 |
|
|
int ncs, |
334 |
greg |
2.29 |
const float wlpt[4] |
335 |
greg |
2.15 |
) |
336 |
greg |
1.1 |
{ |
337 |
greg |
2.27 |
COLOR ciecolor; |
338 |
|
|
|
339 |
|
|
if (ncs == 3) { /* not really a spectrum, so we punt... */ |
340 |
|
|
copycolor(col, scol); |
341 |
greg |
1.2 |
return; |
342 |
|
|
} |
343 |
greg |
2.27 |
scolor2cie(ciecolor, scol, ncs, wlpt); |
344 |
|
|
cie_rgb(col, ciecolor); |
345 |
|
|
} |
346 |
|
|
|
347 |
greg |
1.1 |
|
348 |
greg |
2.27 |
double |
349 |
greg |
2.30 |
scolor2photopic( /* compute scotopic integral for spectral color */ |
350 |
|
|
SCOLOR scol, |
351 |
|
|
int ncs, |
352 |
|
|
const float wlpt[4] |
353 |
|
|
) |
354 |
|
|
{ |
355 |
|
|
if (ncs == 3) |
356 |
|
|
return bright(scol); |
357 |
|
|
|
358 |
|
|
return(spec_dot(scol, ncs, wlpt, cie_y_cumul, CIE_Y_WLMIN, CIE_Y_WLMAX)); |
359 |
|
|
} |
360 |
|
|
|
361 |
|
|
|
362 |
|
|
double |
363 |
|
|
scolor2scotopic( /* compute Y channel for spectral color */ |
364 |
|
|
SCOLOR scol, |
365 |
|
|
int ncs, |
366 |
|
|
const float wlpt[4] |
367 |
|
|
) |
368 |
|
|
{ |
369 |
|
|
return(spec_dot(scol, ncs, wlpt, scotopic_cumul, SCOTOPIC_WLMIN, SCOTOPIC_WLMAX)); |
370 |
|
|
} |
371 |
|
|
|
372 |
|
|
|
373 |
|
|
double |
374 |
|
|
scolor2melanopic( /* compute melanopic integral for spectral color */ |
375 |
|
|
SCOLOR scol, |
376 |
|
|
int ncs, |
377 |
|
|
const float wlpt[4] |
378 |
|
|
) |
379 |
|
|
{ |
380 |
|
|
return(spec_dot(scol, ncs, wlpt, melanopic_cumul, MELANOPIC_WLMIN, MELANOPIC_WLMAX)); |
381 |
|
|
} |
382 |
|
|
|
383 |
|
|
|
384 |
|
|
double |
385 |
greg |
2.27 |
scolor_photopic( /* compute scotopic integral for spectral color */ |
386 |
|
|
SCOLOR scol |
387 |
|
|
) |
388 |
|
|
{ |
389 |
greg |
2.30 |
return(scolor2photopic(scol, NCSAMP, WLPART)); |
390 |
greg |
2.27 |
} |
391 |
|
|
|
392 |
|
|
|
393 |
|
|
double |
394 |
|
|
scolor_scotopic( /* compute Y channel for spectral color */ |
395 |
|
|
SCOLOR scol |
396 |
|
|
) |
397 |
|
|
{ |
398 |
greg |
2.30 |
return(scolor2scotopic(scol, NCSAMP, WLPART)); |
399 |
greg |
2.27 |
} |
400 |
greg |
1.1 |
|
401 |
|
|
|
402 |
greg |
2.27 |
double |
403 |
|
|
scolor_melanopic( /* compute melanopic integral for spectral color */ |
404 |
|
|
SCOLOR scol |
405 |
|
|
) |
406 |
|
|
{ |
407 |
greg |
2.30 |
return(scolor2melanopic(scol, NCSAMP, WLPART)); |
408 |
greg |
1.1 |
} |
409 |
|
|
|
410 |
|
|
|
411 |
greg |
2.11 |
void |
412 |
greg |
2.15 |
cie_rgb( /* convert CIE color to standard RGB */ |
413 |
|
|
COLOR rgb, |
414 |
|
|
COLOR xyz |
415 |
|
|
) |
416 |
greg |
2.8 |
{ |
417 |
|
|
colortrans(rgb, xyz2rgbmat, xyz); |
418 |
|
|
clipgamut(rgb, xyz[CIEY], CGAMUT_LOWER, cblack, cwhite); |
419 |
|
|
} |
420 |
|
|
|
421 |
|
|
|
422 |
|
|
int |
423 |
greg |
2.15 |
clipgamut( /* clip to gamut cube */ |
424 |
|
|
COLOR col, |
425 |
|
|
double brt, |
426 |
|
|
int gamut, |
427 |
|
|
COLOR lower, |
428 |
|
|
COLOR upper |
429 |
|
|
) |
430 |
greg |
2.8 |
{ |
431 |
|
|
int rflags = 0; |
432 |
|
|
double brtmin, brtmax, v, vv; |
433 |
|
|
COLOR cgry; |
434 |
greg |
2.25 |
int i; |
435 |
greg |
2.8 |
/* check for no check */ |
436 |
|
|
if (gamut == 0) return(0); |
437 |
|
|
/* check brightness limits */ |
438 |
|
|
brtmin = 1./3.*(lower[0]+lower[1]+lower[2]); |
439 |
|
|
if (gamut & CGAMUT_LOWER && brt < brtmin) { |
440 |
|
|
copycolor(col, lower); |
441 |
|
|
return(CGAMUT_LOWER); |
442 |
|
|
} |
443 |
|
|
brtmax = 1./3.*(upper[0]+upper[1]+upper[2]); |
444 |
|
|
if (gamut & CGAMUT_UPPER && brt > brtmax) { |
445 |
|
|
copycolor(col, upper); |
446 |
|
|
return(CGAMUT_UPPER); |
447 |
|
|
} |
448 |
|
|
/* compute equivalent grey */ |
449 |
|
|
v = (brt - brtmin)/(brtmax - brtmin); |
450 |
|
|
for (i = 0; i < 3; i++) |
451 |
|
|
cgry[i] = v*upper[i] + (1.-v)*lower[i]; |
452 |
|
|
vv = 1.; /* check each limit */ |
453 |
|
|
for (i = 0; i < 3; i++) |
454 |
|
|
if (gamut & CGAMUT_LOWER && col[i] < lower[i]) { |
455 |
greg |
2.14 |
v = (lower[i] - cgry[i])/(col[i] - cgry[i]); |
456 |
greg |
2.8 |
if (v < vv) vv = v; |
457 |
|
|
rflags |= CGAMUT_LOWER; |
458 |
|
|
} else if (gamut & CGAMUT_UPPER && col[i] > upper[i]) { |
459 |
greg |
2.14 |
v = (upper[i] - cgry[i])/(col[i] - cgry[i]); |
460 |
greg |
2.8 |
if (v < vv) vv = v; |
461 |
|
|
rflags |= CGAMUT_UPPER; |
462 |
|
|
} |
463 |
|
|
if (rflags) /* desaturate to cube face */ |
464 |
|
|
for (i = 0; i < 3; i++) |
465 |
|
|
col[i] = vv*col[i] + (1.-vv)*cgry[i]; |
466 |
|
|
return(rflags); |
467 |
|
|
} |
468 |
|
|
|
469 |
|
|
|
470 |
greg |
2.11 |
void |
471 |
greg |
2.15 |
colortrans( /* convert c1 by mat and put into c2 */ |
472 |
greg |
2.25 |
COLOR c2, |
473 |
|
|
COLORMAT mat, |
474 |
|
|
COLOR c1 |
475 |
greg |
2.15 |
) |
476 |
greg |
1.1 |
{ |
477 |
greg |
2.9 |
COLOR cout; |
478 |
|
|
|
479 |
|
|
cout[0] = mat[0][0]*c1[0] + mat[0][1]*c1[1] + mat[0][2]*c1[2]; |
480 |
|
|
cout[1] = mat[1][0]*c1[0] + mat[1][1]*c1[1] + mat[1][2]*c1[2]; |
481 |
|
|
cout[2] = mat[2][0]*c1[0] + mat[2][1]*c1[1] + mat[2][2]*c1[2]; |
482 |
|
|
|
483 |
|
|
copycolor(c2, cout); |
484 |
greg |
2.4 |
} |
485 |
|
|
|
486 |
|
|
|
487 |
greg |
2.11 |
void |
488 |
greg |
2.15 |
multcolormat( /* multiply m1 by m2 and put into m3 */ |
489 |
|
|
COLORMAT m3, /* m3 can be either m1 or m2 w/o harm */ |
490 |
|
|
COLORMAT m2, |
491 |
|
|
COLORMAT m1 |
492 |
|
|
) |
493 |
greg |
2.4 |
{ |
494 |
greg |
2.5 |
COLORMAT mt; |
495 |
greg |
2.25 |
int i, j; |
496 |
greg |
2.4 |
|
497 |
|
|
for (i = 0; i < 3; i++) |
498 |
greg |
2.5 |
for (j = 0; j < 3; j++) |
499 |
|
|
mt[i][j] = m1[i][0]*m2[0][j] + |
500 |
|
|
m1[i][1]*m2[1][j] + |
501 |
|
|
m1[i][2]*m2[2][j] ; |
502 |
|
|
cpcolormat(m3, mt); |
503 |
|
|
} |
504 |
|
|
|
505 |
|
|
|
506 |
greg |
2.15 |
int |
507 |
|
|
colorprimsOK( /* are color primaries reasonable? */ |
508 |
|
|
RGBPRIMS pr |
509 |
|
|
) |
510 |
|
|
{ |
511 |
greg |
2.20 |
int i, j; |
512 |
greg |
2.26 |
/* check white point */ |
513 |
|
|
if ((pr[3][CIEX] <= CEPS) | (pr[3][CIEX] >= 1.-CEPS) | |
514 |
|
|
(pr[3][CIEY] <= CEPS) | (pr[3][CIEY] >= 1.-CEPS)) |
515 |
|
|
return(0); |
516 |
|
|
for (i = 3; i--; ) /* check for XYZ color primaries */ |
517 |
|
|
if (!CEQ(pr[i][CIEX],(i==0)) | !CEQ(pr[i][CIEY],(i==1))) |
518 |
|
|
break; |
519 |
|
|
if (i < 0) |
520 |
|
|
return(-1); /* flag as XYZ color space */ |
521 |
|
|
/* check color primaries */ |
522 |
greg |
2.22 |
for (i = 0; i < 3; i++) { |
523 |
greg |
2.24 |
if ((pr[i][CIEX] <= -2.) | (pr[i][CIEY] <= -2.)) |
524 |
greg |
2.15 |
return(0); |
525 |
greg |
2.24 |
if ((pr[i][CIEX] >= 3.) | (pr[i][CIEY] >= 3.)) |
526 |
greg |
2.17 |
return(0); |
527 |
greg |
2.24 |
if (pr[i][CIEX] + pr[i][CIEY] <= -2.) |
528 |
greg |
2.21 |
return(0); |
529 |
greg |
2.24 |
if (pr[i][CIEX] + pr[i][CIEY] >= 3.) |
530 |
greg |
2.15 |
return(0); |
531 |
|
|
} |
532 |
greg |
2.26 |
for (i = 0; i < 4; i++) /* make sure space is 3-dimensional */ |
533 |
greg |
2.20 |
for (j = i+1; j < 4; j++) |
534 |
greg |
2.26 |
if (CEQ(pr[i][CIEX],pr[j][CIEX]) & |
535 |
greg |
2.20 |
CEQ(pr[i][CIEY],pr[j][CIEY])) |
536 |
|
|
return(0); |
537 |
greg |
2.15 |
return(1); |
538 |
|
|
} |
539 |
|
|
|
540 |
|
|
|
541 |
|
|
|
542 |
|
|
int |
543 |
|
|
compxyz2rgbmat( /* compute conversion from CIE to RGB space */ |
544 |
|
|
COLORMAT mat, |
545 |
greg |
2.25 |
RGBPRIMS pr |
546 |
greg |
2.15 |
) |
547 |
greg |
2.5 |
{ |
548 |
|
|
double C_rD, C_gD, C_bD; |
549 |
|
|
|
550 |
greg |
2.6 |
if (pr == stdprims) { /* can use xyz2rgbmat */ |
551 |
|
|
cpcolormat(mat, xyz2rgbmat); |
552 |
greg |
2.16 |
return(1); |
553 |
greg |
2.6 |
} |
554 |
greg |
2.27 |
if (pr == xyzprims) { /* identity */ |
555 |
|
|
memset(mat, 0, sizeof(COLORMAT)); |
556 |
|
|
mat[0][0] = mat[1][1] = mat[2][2] = 1.f; |
557 |
|
|
return(1); |
558 |
|
|
} |
559 |
greg |
2.15 |
if (CEQ(pr[WHT][CIEX],0.) | CEQ(pr[WHT][CIEY],0.)) |
560 |
|
|
return(0); |
561 |
greg |
2.5 |
C_rD = (1./pr[WHT][CIEY]) * |
562 |
|
|
( pr[WHT][CIEX]*(pr[GRN][CIEY] - pr[BLU][CIEY]) - |
563 |
|
|
pr[WHT][CIEY]*(pr[GRN][CIEX] - pr[BLU][CIEX]) + |
564 |
|
|
pr[GRN][CIEX]*pr[BLU][CIEY] - pr[BLU][CIEX]*pr[GRN][CIEY] ) ; |
565 |
greg |
2.15 |
if (CEQ(C_rD,0.)) |
566 |
|
|
return(0); |
567 |
greg |
2.5 |
C_gD = (1./pr[WHT][CIEY]) * |
568 |
|
|
( pr[WHT][CIEX]*(pr[BLU][CIEY] - pr[RED][CIEY]) - |
569 |
|
|
pr[WHT][CIEY]*(pr[BLU][CIEX] - pr[RED][CIEX]) - |
570 |
|
|
pr[RED][CIEX]*pr[BLU][CIEY] + pr[BLU][CIEX]*pr[RED][CIEY] ) ; |
571 |
greg |
2.15 |
if (CEQ(C_gD,0.)) |
572 |
|
|
return(0); |
573 |
greg |
2.5 |
C_bD = (1./pr[WHT][CIEY]) * |
574 |
|
|
( pr[WHT][CIEX]*(pr[RED][CIEY] - pr[GRN][CIEY]) - |
575 |
|
|
pr[WHT][CIEY]*(pr[RED][CIEX] - pr[GRN][CIEX]) + |
576 |
|
|
pr[RED][CIEX]*pr[GRN][CIEY] - pr[GRN][CIEX]*pr[RED][CIEY] ) ; |
577 |
greg |
2.15 |
if (CEQ(C_bD,0.)) |
578 |
|
|
return(0); |
579 |
greg |
2.5 |
mat[0][0] = (pr[GRN][CIEY] - pr[BLU][CIEY] - |
580 |
|
|
pr[BLU][CIEX]*pr[GRN][CIEY] + |
581 |
|
|
pr[BLU][CIEY]*pr[GRN][CIEX])/C_rD ; |
582 |
|
|
mat[0][1] = (pr[BLU][CIEX] - pr[GRN][CIEX] - |
583 |
|
|
pr[BLU][CIEX]*pr[GRN][CIEY] + |
584 |
|
|
pr[GRN][CIEX]*pr[BLU][CIEY])/C_rD ; |
585 |
|
|
mat[0][2] = (pr[GRN][CIEX]*pr[BLU][CIEY] - |
586 |
|
|
pr[BLU][CIEX]*pr[GRN][CIEY])/C_rD ; |
587 |
|
|
mat[1][0] = (pr[BLU][CIEY] - pr[RED][CIEY] - |
588 |
|
|
pr[BLU][CIEY]*pr[RED][CIEX] + |
589 |
|
|
pr[RED][CIEY]*pr[BLU][CIEX])/C_gD ; |
590 |
|
|
mat[1][1] = (pr[RED][CIEX] - pr[BLU][CIEX] - |
591 |
|
|
pr[RED][CIEX]*pr[BLU][CIEY] + |
592 |
|
|
pr[BLU][CIEX]*pr[RED][CIEY])/C_gD ; |
593 |
|
|
mat[1][2] = (pr[BLU][CIEX]*pr[RED][CIEY] - |
594 |
|
|
pr[RED][CIEX]*pr[BLU][CIEY])/C_gD ; |
595 |
|
|
mat[2][0] = (pr[RED][CIEY] - pr[GRN][CIEY] - |
596 |
|
|
pr[RED][CIEY]*pr[GRN][CIEX] + |
597 |
|
|
pr[GRN][CIEY]*pr[RED][CIEX])/C_bD ; |
598 |
|
|
mat[2][1] = (pr[GRN][CIEX] - pr[RED][CIEX] - |
599 |
|
|
pr[GRN][CIEX]*pr[RED][CIEY] + |
600 |
|
|
pr[RED][CIEX]*pr[GRN][CIEY])/C_bD ; |
601 |
|
|
mat[2][2] = (pr[RED][CIEX]*pr[GRN][CIEY] - |
602 |
|
|
pr[GRN][CIEX]*pr[RED][CIEY])/C_bD ; |
603 |
greg |
2.15 |
return(1); |
604 |
greg |
2.5 |
} |
605 |
|
|
|
606 |
|
|
|
607 |
greg |
2.15 |
int |
608 |
|
|
comprgb2xyzmat( /* compute conversion from RGB to CIE space */ |
609 |
|
|
COLORMAT mat, |
610 |
greg |
2.25 |
RGBPRIMS pr |
611 |
greg |
2.15 |
) |
612 |
greg |
2.5 |
{ |
613 |
|
|
double C_rD, C_gD, C_bD, D; |
614 |
|
|
|
615 |
greg |
2.6 |
if (pr == stdprims) { /* can use rgb2xyzmat */ |
616 |
|
|
cpcolormat(mat, rgb2xyzmat); |
617 |
greg |
2.16 |
return(1); |
618 |
greg |
2.6 |
} |
619 |
greg |
2.27 |
if (pr == xyzprims) { /* identity */ |
620 |
|
|
memset(mat, 0, sizeof(COLORMAT)); |
621 |
|
|
mat[0][0] = mat[1][1] = mat[2][2] = 1.f; |
622 |
|
|
return(1); |
623 |
|
|
} |
624 |
greg |
2.15 |
if (CEQ(pr[WHT][CIEX],0.) | CEQ(pr[WHT][CIEY],0.)) |
625 |
|
|
return(0); |
626 |
greg |
2.5 |
C_rD = (1./pr[WHT][CIEY]) * |
627 |
|
|
( pr[WHT][CIEX]*(pr[GRN][CIEY] - pr[BLU][CIEY]) - |
628 |
|
|
pr[WHT][CIEY]*(pr[GRN][CIEX] - pr[BLU][CIEX]) + |
629 |
|
|
pr[GRN][CIEX]*pr[BLU][CIEY] - pr[BLU][CIEX]*pr[GRN][CIEY] ) ; |
630 |
|
|
C_gD = (1./pr[WHT][CIEY]) * |
631 |
|
|
( pr[WHT][CIEX]*(pr[BLU][CIEY] - pr[RED][CIEY]) - |
632 |
|
|
pr[WHT][CIEY]*(pr[BLU][CIEX] - pr[RED][CIEX]) - |
633 |
|
|
pr[RED][CIEX]*pr[BLU][CIEY] + pr[BLU][CIEX]*pr[RED][CIEY] ) ; |
634 |
|
|
C_bD = (1./pr[WHT][CIEY]) * |
635 |
|
|
( pr[WHT][CIEX]*(pr[RED][CIEY] - pr[GRN][CIEY]) - |
636 |
|
|
pr[WHT][CIEY]*(pr[RED][CIEX] - pr[GRN][CIEX]) + |
637 |
|
|
pr[RED][CIEX]*pr[GRN][CIEY] - pr[GRN][CIEX]*pr[RED][CIEY] ) ; |
638 |
|
|
D = pr[RED][CIEX]*(pr[GRN][CIEY] - pr[BLU][CIEY]) + |
639 |
|
|
pr[GRN][CIEX]*(pr[BLU][CIEY] - pr[RED][CIEY]) + |
640 |
|
|
pr[BLU][CIEX]*(pr[RED][CIEY] - pr[GRN][CIEY]) ; |
641 |
greg |
2.15 |
if (CEQ(D,0.)) |
642 |
|
|
return(0); |
643 |
greg |
2.5 |
mat[0][0] = pr[RED][CIEX]*C_rD/D; |
644 |
|
|
mat[0][1] = pr[GRN][CIEX]*C_gD/D; |
645 |
|
|
mat[0][2] = pr[BLU][CIEX]*C_bD/D; |
646 |
|
|
mat[1][0] = pr[RED][CIEY]*C_rD/D; |
647 |
|
|
mat[1][1] = pr[GRN][CIEY]*C_gD/D; |
648 |
|
|
mat[1][2] = pr[BLU][CIEY]*C_bD/D; |
649 |
|
|
mat[2][0] = (1.-pr[RED][CIEX]-pr[RED][CIEY])*C_rD/D; |
650 |
|
|
mat[2][1] = (1.-pr[GRN][CIEX]-pr[GRN][CIEY])*C_gD/D; |
651 |
|
|
mat[2][2] = (1.-pr[BLU][CIEX]-pr[BLU][CIEY])*C_bD/D; |
652 |
greg |
2.15 |
return(1); |
653 |
greg |
2.5 |
} |
654 |
|
|
|
655 |
|
|
|
656 |
greg |
2.15 |
int |
657 |
|
|
comprgb2rgbmat( /* compute conversion from RGB1 to RGB2 */ |
658 |
|
|
COLORMAT mat, |
659 |
|
|
RGBPRIMS pr1, |
660 |
|
|
RGBPRIMS pr2 |
661 |
|
|
) |
662 |
greg |
2.5 |
{ |
663 |
|
|
COLORMAT pr1toxyz, xyztopr2; |
664 |
|
|
|
665 |
greg |
2.6 |
if (pr1 == pr2) { |
666 |
greg |
2.27 |
memset(mat, 0, sizeof(COLORMAT)); |
667 |
|
|
mat[0][0] = mat[1][1] = mat[2][2] = 1.f; |
668 |
greg |
2.16 |
return(1); |
669 |
greg |
2.6 |
} |
670 |
greg |
2.15 |
if (!comprgb2xyzmat(pr1toxyz, pr1)) |
671 |
|
|
return(0); |
672 |
|
|
if (!compxyz2rgbmat(xyztopr2, pr2)) |
673 |
|
|
return(0); |
674 |
greg |
2.5 |
/* combine transforms */ |
675 |
|
|
multcolormat(mat, pr1toxyz, xyztopr2); |
676 |
greg |
2.15 |
return(1); |
677 |
greg |
2.11 |
} |
678 |
|
|
|
679 |
|
|
|
680 |
greg |
2.15 |
int |
681 |
|
|
compxyzWBmat( /* CIE von Kries transform from wht1 to wht2 */ |
682 |
|
|
COLORMAT mat, |
683 |
|
|
float wht1[2], |
684 |
|
|
float wht2[2] |
685 |
|
|
) |
686 |
greg |
2.11 |
{ |
687 |
|
|
COLOR cw1, cw2; |
688 |
|
|
if (XYEQ(wht1,wht2)) { |
689 |
greg |
2.27 |
memset(mat, 0, sizeof(COLORMAT)); |
690 |
|
|
mat[0][0] = mat[1][1] = mat[2][2] = 1.f; |
691 |
greg |
2.15 |
return(1); |
692 |
greg |
2.11 |
} |
693 |
greg |
2.15 |
if (CEQ(wht1[CIEX],0.) | CEQ(wht1[CIEY],0.)) |
694 |
|
|
return(0); |
695 |
greg |
2.11 |
cw1[RED] = wht1[CIEX]/wht1[CIEY]; |
696 |
|
|
cw1[GRN] = 1.; |
697 |
|
|
cw1[BLU] = (1. - wht1[CIEX] - wht1[CIEY])/wht1[CIEY]; |
698 |
|
|
colortrans(cw1, vkmat, cw1); |
699 |
greg |
2.15 |
if (CEQ(wht2[CIEX],0.) | CEQ(wht2[CIEY],0.)) |
700 |
|
|
return(0); |
701 |
greg |
2.11 |
cw2[RED] = wht2[CIEX]/wht2[CIEY]; |
702 |
|
|
cw2[GRN] = 1.; |
703 |
|
|
cw2[BLU] = (1. - wht2[CIEX] - wht2[CIEY])/wht2[CIEY]; |
704 |
|
|
colortrans(cw2, vkmat, cw2); |
705 |
greg |
2.15 |
if (CEQ(cw1[RED],0.) | CEQ(cw1[GRN],0.) | CEQ(cw1[BLU],0.)) |
706 |
|
|
return(0); |
707 |
greg |
2.11 |
mat[0][0] = cw2[RED]/cw1[RED]; |
708 |
|
|
mat[1][1] = cw2[GRN]/cw1[GRN]; |
709 |
|
|
mat[2][2] = cw2[BLU]/cw1[BLU]; |
710 |
|
|
mat[0][1] = mat[0][2] = mat[1][0] = |
711 |
|
|
mat[1][2] = mat[2][0] = mat[2][1] = 0.0; |
712 |
|
|
multcolormat(mat, vkmat, mat); |
713 |
|
|
multcolormat(mat, mat, ivkmat); |
714 |
greg |
2.15 |
return(1); |
715 |
greg |
2.11 |
} |
716 |
|
|
|
717 |
|
|
|
718 |
greg |
2.15 |
int |
719 |
|
|
compxyz2rgbWBmat( /* von Kries conversion from CIE to RGB space */ |
720 |
|
|
COLORMAT mat, |
721 |
|
|
RGBPRIMS pr |
722 |
|
|
) |
723 |
greg |
2.11 |
{ |
724 |
|
|
COLORMAT wbmat; |
725 |
|
|
|
726 |
greg |
2.15 |
if (!compxyz2rgbmat(mat, pr)) |
727 |
|
|
return(0); |
728 |
greg |
2.11 |
if (XYEQ(pr[WHT],xyneu)) |
729 |
greg |
2.15 |
return(1); |
730 |
|
|
if (!compxyzWBmat(wbmat, xyneu, pr[WHT])) |
731 |
|
|
return(0); |
732 |
greg |
2.11 |
multcolormat(mat, wbmat, mat); |
733 |
greg |
2.15 |
return(1); |
734 |
greg |
2.11 |
} |
735 |
|
|
|
736 |
greg |
2.15 |
int |
737 |
|
|
comprgb2xyzWBmat( /* von Kries conversion from RGB to CIE space */ |
738 |
|
|
COLORMAT mat, |
739 |
|
|
RGBPRIMS pr |
740 |
|
|
) |
741 |
greg |
2.11 |
{ |
742 |
|
|
COLORMAT wbmat; |
743 |
|
|
|
744 |
greg |
2.15 |
if (!comprgb2xyzmat(mat, pr)) |
745 |
|
|
return(0); |
746 |
greg |
2.11 |
if (XYEQ(pr[WHT],xyneu)) |
747 |
greg |
2.15 |
return(1); |
748 |
|
|
if (!compxyzWBmat(wbmat, pr[WHT], xyneu)) |
749 |
|
|
return(0); |
750 |
greg |
2.11 |
multcolormat(mat, mat, wbmat); |
751 |
greg |
2.15 |
return(1); |
752 |
greg |
2.11 |
} |
753 |
|
|
|
754 |
greg |
2.15 |
int |
755 |
|
|
comprgb2rgbWBmat( /* von Kries conversion from RGB1 to RGB2 */ |
756 |
|
|
COLORMAT mat, |
757 |
|
|
RGBPRIMS pr1, |
758 |
|
|
RGBPRIMS pr2 |
759 |
|
|
) |
760 |
greg |
2.11 |
{ |
761 |
|
|
COLORMAT pr1toxyz, xyztopr2, wbmat; |
762 |
|
|
|
763 |
|
|
if (pr1 == pr2) { |
764 |
greg |
2.27 |
memset(mat, 0, sizeof(COLORMAT)); |
765 |
|
|
mat[0][0] = mat[1][1] = mat[2][2] = 1.f; |
766 |
greg |
2.15 |
return(1); |
767 |
greg |
2.11 |
} |
768 |
greg |
2.15 |
if (!comprgb2xyzmat(pr1toxyz, pr1)) |
769 |
|
|
return(0); |
770 |
|
|
if (!compxyzWBmat(wbmat, pr1[WHT], pr2[WHT])) |
771 |
|
|
return(0); |
772 |
|
|
if (!compxyz2rgbmat(xyztopr2, pr2)) |
773 |
|
|
return(0); |
774 |
greg |
2.11 |
/* combine transforms */ |
775 |
|
|
multcolormat(mat, pr1toxyz, wbmat); |
776 |
|
|
multcolormat(mat, mat, xyztopr2); |
777 |
greg |
2.15 |
return(1); |
778 |
greg |
1.1 |
} |