12 |
|
|
13 |
|
#include <stdio.h> |
14 |
|
#include <string.h> |
15 |
+ |
#include <math.h> |
16 |
|
#include "color.h" |
17 |
|
|
18 |
|
#define CEPS 1e-4 /* color epsilon */ |
25 |
|
RGBPRIMS stdprims = STDPRIMS; /* standard primary chromaticities */ |
26 |
|
RGBPRIMS xyzprims = {1,0, 0,1, 0,0, 1.f/3.f,1.f/3.f}; |
27 |
|
|
28 |
< |
COLOR cblack = BLKCOLOR; /* global black color */ |
29 |
< |
COLOR cwhite = WHTCOLOR; /* global white color */ |
28 |
> |
const COLOR cblack = BLKCOLOR; /* global black color */ |
29 |
> |
const COLOR cwhite = WHTCOLOR; /* global white color */ |
30 |
> |
const SCOLOR scblack = {0}; /* global black spectrum */ |
31 |
|
|
32 |
|
float xyneu[2] = {1./3., 1./3.}; /* neutral xy chromaticities */ |
33 |
|
|
272 |
|
COLOR ciecolor; |
273 |
|
|
274 |
|
spec_cie(ciecolor, s, e); |
275 |
< |
cie_rgb(col, ciecolor); |
275 |
> |
colortrans(col, xyz2rgbmat, ciecolor); |
276 |
|
} |
277 |
|
|
278 |
|
|
279 |
|
static double |
280 |
|
spec_dot( /* spectrum dot-product with cumulative observer */ |
281 |
< |
SCOLOR scol, |
281 |
> |
const SCOLOR scol, |
282 |
|
int ncs, |
283 |
< |
float wlpt[4], |
283 |
> |
const float wlpt[4], |
284 |
|
const unsigned short cumul[], |
285 |
|
int wlmin, |
286 |
|
int wlmax |
313 |
|
void |
314 |
|
scolor2cie( /* accurate conversion from spectrum to XYZ */ |
315 |
|
COLOR col, |
316 |
< |
SCOLOR scol, |
316 |
> |
const SCOLOR scol, |
317 |
|
int ncs, |
318 |
< |
float wlpt[4] |
318 |
> |
const float wlpt[4] |
319 |
|
) |
320 |
|
{ |
321 |
|
if (ncs == 3) { /* not a spectrum! */ |
331 |
|
void |
332 |
|
scolor2rgb( /* accurate conversion from spectrum to RGB */ |
333 |
|
COLOR col, |
334 |
< |
SCOLOR scol, |
334 |
> |
const SCOLOR scol, |
335 |
|
int ncs, |
336 |
< |
float wlpt[4] |
336 |
> |
const float wlpt[4] |
337 |
|
) |
338 |
|
{ |
339 |
|
COLOR ciecolor; |
347 |
|
} |
348 |
|
|
349 |
|
|
350 |
+ |
void |
351 |
+ |
scolor_out( /* prepare (spectral) color for output */ |
352 |
+ |
COLORV *cout, |
353 |
+ |
RGBPRIMS pr, |
354 |
+ |
const SCOLOR cres |
355 |
+ |
) |
356 |
+ |
{ |
357 |
+ |
static COLORMAT xyz2myp; |
358 |
+ |
static RGBPRIMP lastp = NULL; |
359 |
+ |
|
360 |
+ |
if (!pr) { /* output is spectral */ |
361 |
+ |
copyscolor(cout, cres); |
362 |
+ |
} else if (pr == stdprims) { /* output is standard RGB */ |
363 |
+ |
scolor_rgb(cout, cres); |
364 |
+ |
} else if (pr == xyzprims) { /* output is XYZ */ |
365 |
+ |
scolor_cie(cout, cres); |
366 |
+ |
scalecolor(cout, WHTEFFICACY); |
367 |
+ |
} else if (NCSAMP > 3) { /* spectral -> custom RGB */ |
368 |
+ |
COLOR xyz; |
369 |
+ |
if (lastp != pr) |
370 |
+ |
compxyz2rgbWBmat(xyz2myp, lastp=pr); |
371 |
+ |
scolor_cie(xyz, cres); |
372 |
+ |
colortrans(cout, xyz2myp, xyz); |
373 |
+ |
clipgamut(cout, xyz[CIEY], CGAMUT_LOWER, cblack, cwhite); |
374 |
+ |
} else { /* else copy unknown RGB */ |
375 |
+ |
copycolor(cout, cres); |
376 |
+ |
} |
377 |
+ |
} |
378 |
+ |
|
379 |
+ |
|
380 |
|
double |
381 |
< |
scolor_photopic( /* compute scotopic integral for spectral color */ |
382 |
< |
SCOLOR scol |
381 |
> |
scolor2photopic( /* compute scotopic integral for spectral color */ |
382 |
> |
const SCOLOR scol, |
383 |
> |
int ncs, |
384 |
> |
const float wlpt[4] |
385 |
|
) |
386 |
|
{ |
387 |
< |
if (NCSAMP == 3) |
387 |
> |
if (ncs == 3) |
388 |
|
return bright(scol); |
389 |
|
|
390 |
< |
return(spec_dot(scol, NCSAMP, WLPART, cie_y_cumul, CIE_Y_WLMIN, CIE_Y_WLMAX)); |
390 |
> |
return(spec_dot(scol, ncs, wlpt, cie_y_cumul, CIE_Y_WLMIN, CIE_Y_WLMAX)); |
391 |
|
} |
392 |
|
|
393 |
|
|
394 |
|
double |
395 |
+ |
scolor2scotopic( /* compute Y channel for spectral color */ |
396 |
+ |
const SCOLOR scol, |
397 |
+ |
int ncs, |
398 |
+ |
const float wlpt[4] |
399 |
+ |
) |
400 |
+ |
{ |
401 |
+ |
return(spec_dot(scol, ncs, wlpt, scotopic_cumul, SCOTOPIC_WLMIN, SCOTOPIC_WLMAX)); |
402 |
+ |
} |
403 |
+ |
|
404 |
+ |
|
405 |
+ |
double |
406 |
+ |
scolor2melanopic( /* compute melanopic integral for spectral color */ |
407 |
+ |
const SCOLOR scol, |
408 |
+ |
int ncs, |
409 |
+ |
const float wlpt[4] |
410 |
+ |
) |
411 |
+ |
{ |
412 |
+ |
return(spec_dot(scol, ncs, wlpt, melanopic_cumul, MELANOPIC_WLMIN, MELANOPIC_WLMAX)); |
413 |
+ |
} |
414 |
+ |
|
415 |
+ |
|
416 |
+ |
double |
417 |
+ |
scolor_photopic( /* compute scotopic integral for spectral color */ |
418 |
+ |
const SCOLOR scol |
419 |
+ |
) |
420 |
+ |
{ |
421 |
+ |
return(scolor2photopic(scol, NCSAMP, WLPART)); |
422 |
+ |
} |
423 |
+ |
|
424 |
+ |
|
425 |
+ |
double |
426 |
|
scolor_scotopic( /* compute Y channel for spectral color */ |
427 |
< |
SCOLOR scol |
427 |
> |
const SCOLOR scol |
428 |
|
) |
429 |
|
{ |
430 |
< |
return(spec_dot(scol, NCSAMP, WLPART, scotopic_cumul, SCOTOPIC_WLMIN, SCOTOPIC_WLMAX)); |
430 |
> |
return(scolor2scotopic(scol, NCSAMP, WLPART)); |
431 |
|
} |
432 |
|
|
433 |
|
|
434 |
|
double |
435 |
|
scolor_melanopic( /* compute melanopic integral for spectral color */ |
436 |
< |
SCOLOR scol |
436 |
> |
const SCOLOR scol |
437 |
|
) |
438 |
|
{ |
439 |
< |
return(spec_dot(scol, NCSAMP, WLPART, melanopic_cumul, MELANOPIC_WLMIN, MELANOPIC_WLMAX)); |
439 |
> |
return(scolor2melanopic(scol, NCSAMP, WLPART)); |
440 |
|
} |
441 |
|
|
442 |
|
|
443 |
|
void |
444 |
+ |
convertscolorcol( /* any uniform spectrum to working */ |
445 |
+ |
SCOLOR rcol, |
446 |
+ |
const COLORV src[], |
447 |
+ |
int snc, |
448 |
+ |
double swl0, |
449 |
+ |
double swl1 |
450 |
+ |
) |
451 |
+ |
{ |
452 |
+ |
if (NCSAMP > 3) { /* spectrum -> spectrum */ |
453 |
+ |
convertscolor(rcol, NCSAMP, WLPART[0], WLPART[3], |
454 |
+ |
src, snc, swl0, swl1); |
455 |
+ |
} else if ((snc <= MAXCSAMP) & (swl0 > swl1)) { |
456 |
+ |
float wlpt[4]; /* no intermediate conversion needed */ |
457 |
+ |
wlpt[0] = swl0; wlpt[3] = swl1; |
458 |
+ |
wlpt[1] = WLPART[1]; wlpt[2] = WLPART[2]; |
459 |
+ |
scolor2rgb(rcol, (COLORV *)src, snc, wlpt); |
460 |
+ |
} else { |
461 |
+ |
SCOLOR dcol; /* else convert spectrum first */ |
462 |
+ |
int dnc = snc*(WLPART[0] - WLPART[3])/fabs(swl0 - swl1) + .99; |
463 |
+ |
if (dnc > MAXCSAMP) dnc = MAXCSAMP; |
464 |
+ |
convertscolor(dcol, dnc, WLPART[0], WLPART[3], src, snc, swl0, swl1); |
465 |
+ |
scolor2rgb(rcol, dcol, dnc, WLPART); |
466 |
+ |
} |
467 |
+ |
} |
468 |
+ |
|
469 |
+ |
|
470 |
+ |
void |
471 |
|
cie_rgb( /* convert CIE color to standard RGB */ |
472 |
|
COLOR rgb, |
473 |
< |
COLOR xyz |
473 |
> |
const COLOR xyz |
474 |
|
) |
475 |
|
{ |
476 |
|
colortrans(rgb, xyz2rgbmat, xyz); |
483 |
|
COLOR col, |
484 |
|
double brt, |
485 |
|
int gamut, |
486 |
< |
COLOR lower, |
487 |
< |
COLOR upper |
486 |
> |
const COLOR lower, |
487 |
> |
const COLOR upper |
488 |
|
) |
489 |
|
{ |
490 |
|
int rflags = 0; |
529 |
|
void |
530 |
|
colortrans( /* convert c1 by mat and put into c2 */ |
531 |
|
COLOR c2, |
532 |
< |
COLORMAT mat, |
533 |
< |
COLOR c1 |
532 |
> |
const COLORMAT mat, |
533 |
> |
const COLOR c1 |
534 |
|
) |
535 |
|
{ |
536 |
|
COLOR cout; |
546 |
|
void |
547 |
|
multcolormat( /* multiply m1 by m2 and put into m3 */ |
548 |
|
COLORMAT m3, /* m3 can be either m1 or m2 w/o harm */ |
549 |
< |
COLORMAT m2, |
550 |
< |
COLORMAT m1 |
549 |
> |
const COLORMAT m2, |
550 |
> |
const COLORMAT m1 |
551 |
|
) |
552 |
|
{ |
553 |
|
COLORMAT mt; |
739 |
|
int |
740 |
|
compxyzWBmat( /* CIE von Kries transform from wht1 to wht2 */ |
741 |
|
COLORMAT mat, |
742 |
< |
float wht1[2], |
743 |
< |
float wht2[2] |
742 |
> |
const float wht1[2], |
743 |
> |
const float wht2[2] |
744 |
|
) |
745 |
|
{ |
746 |
|
COLOR cw1, cw2; |