1 
2 #ifndef XSPECT_H
3 #define XSPECT_H
4 
5 /*
6  * Author:  Graeme W. Gill
7  * Date:    21/6/01
8  * Version: 1.00
9  *
10  * Copyright 2000 - 2010 Graeme W. Gill
11  * All rights reserved.
12  *
13  * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
14  * see the License2.txt file for licencing details.
15  */
16 
17 /*
18  * This class supports converting spectral samples
19  * into CIE XYZ or D50 Lab tristimulous values.
20  */
21 
22 /*
23  * TTBD:
24  *
25  */
26 
27 #ifndef SALONEINSTLIB
28 #include "icc.h"		/* icclib ICC definitions */
29 #else /* SALONEINSTLIB */
30 #include "sa_conv.h"		/* fake icclib ICC definitions */
31 #endif /* SALONEINSTLIB */
32 
33 #ifdef __cplusplus
34 	extern "C" {
35 #endif
36 
37 /* ------------------------------------------------------------------------------ */
38 
39 /* Type of measurement result */
40 typedef enum {						/* XYZ units,      Spectral units */
41 	inst_mrt_none           = 0,	/* Not set */
42 	inst_mrt_emission       = 1,	/* cd/m^2,         mW/(m^2.sr.nm) */
43 	inst_mrt_ambient        = 2,	/* Lux             mW/(m^2.nm) */
44 	inst_mrt_emission_flash = 3,	/* cd.s/m^2,       mW.s/(m^2.sr.nm) */
45 	inst_mrt_ambient_flash  = 4,	/* Lux.s           mW.s/(m^2.nm) */
46 	inst_mrt_reflective     = 5,	/* %,              %/nm */
47 	inst_mrt_transmissive   = 6,	/* %,              %/nm */
48 	inst_mrt_sensitivity    = 7,	/* %,              %/nm */
49 	inst_mrt_frequency      = 8		/* Hz */
50 } inst_meas_type;
51 
52 /* Return a string describing the inst_meas_type */
53 char *meas_type2str(inst_meas_type mt);
54 
55 /* ------------------------------------------------------------------------------ */
56 
57 /* Structure for conveying spectral information */
58 
59 /* NOTE :- should ditch norm, and replace it by */
60 /* "units", ie. reflectance/transmittance 0..1, 0..100%, */
61 /* W/nm/m^2 or mW/nm/m^2 */
62 #define XSPECT_MAX_BANDS 601		/* Enought for 1nm from 300 to 900 */
63 
64 typedef struct {
65 	int    spec_n;					/* Number of spectral bands, 0 if not valid */
66 	double spec_wl_short;			/* First reading wavelength in nm (shortest) */
67 	double spec_wl_long;			/* Last reading wavelength in nm (longest) */
68 	double norm;					/* Normalising scale value, ie. 1, 100 etc. */
69 	double spec[XSPECT_MAX_BANDS];	/* Spectral value, shortest to longest */
70 } xspect;
71 
72 /* Some helpful macro's: */
73 
74 /* Copy everything except the spectral values */
75 #define XSPECT_COPY_INFO(PDST, PSRC) 						\
76  (PDST)->spec_n = (PSRC)->spec_n,							\
77  (PDST)->spec_wl_short = (PSRC)->spec_wl_short,				\
78  (PDST)->spec_wl_long = (PSRC)->spec_wl_long,				\
79  (PDST)->norm = (PSRC)->norm
80 
81 /* Given an index and the sampling ranges, compute the sample wavelength */
82 #define XSPECT_WL(SHORT, LONG, N, IX) \
83 ((SHORT) + (double)(IX) * ((LONG) - (SHORT))/((N)-1.0))
84 
85 /* Given the address of an xspect and an index, compute the sample wavelegth */
86 #define XSPECT_XWL(PXSP, IX) \
87 (((PXSP)->spec_wl_short) + (double)(IX) * (((PXSP)->spec_wl_long) - ((PXSP)->spec_wl_short))/(((PXSP)->spec_n)-1.0))
88 
89 /* Given a wavelength and the sampling ranges, compute the double index */
90 #define XSPECT_DIX(SHORT, LONG, N, WL) \
91 (((N)-1.0) * ((WL) - (SHORT))/((LONG) - (SHORT)))
92 
93 /* Given the wavelength and address of an xspect, compute the double index */
94 #define XSPECT_XDIX(PXSP, WL) \
95 (((PXSP)->spec_n-1.0) * ((WL) - ((PXSP)->spec_wl_short))/(((PXSP)->spec_wl_long) - ((PXSP)->spec_wl_short)))
96 
97 /* Given a wavelength and the sampling ranges, compute the nearest index */
98 #define XSPECT_IX(SHORT, LONG, N, WL) \
99 ((int)floor(XSPECT_DIX(SHORT, LONG, N, WL) + 0.5))
100 
101 /* Given a wavelength and address of an xspect, compute the nearest index */
102 #define XSPECT_XIX(PXSP, WL) \
103 ((int)floor(XSPECT_XDIX(PXSP, WL) + 0.5))
104 
105 #ifndef SALONEINSTLIB
106 
107 /* Single spectrum utility functions. Return NZ if error */
108 int write_xspect(char *fname, inst_meas_type mt, xspect *s);
109 int read_xspect(xspect *sp, inst_meas_type *mt, char *fname);
110 
111 /* CMF utility functions. Return NZ if error */
112 int write_cmf(char *fname, xspect cmf[3]);
113 int read_cmf(xspect cmf[3], char *fname);
114 
115 /* Save a set of nspec spectrum to a CGATS file. Return NZ if error */
116 /* type 0 = SPECT, 1 = CMF */
117 int write_nxspect(char *fname, inst_meas_type mt, xspect *sp, int nspec, int type);
118 
119 /* Restore a set of up to nspec spectrum from a CGATS file. Return NZ if error */
120 /* type  = any, 1 = SPECT, 2 = CMF, 3 = both */
121 int read_nxspect(xspect *sp, inst_meas_type *mt,
122 	             char *fname, int *nret, int off, int nspec, int type);
123 
124 #endif /* !SALONEINSTLIB*/
125 
126 /* Get interpolated value at wavelenth (not normalised) */
127 double value_xspect(xspect *sp, double wl);
128 
129 /* De-normalize and set normalisation factor to 1.0 */
130 void xspect_denorm(xspect *sp);
131 
132 #ifndef SALONEINSTLIB
133 /* Convert from one xspect type to another */
134 void xspect2xspect(xspect *dst, xspect *targ, xspect *src);
135 
136 /* Plot up to 3 spectra */
137 void xspect_plot_w(xspect *sp1, xspect *sp2, xspect *sp3, int wait);
138 
139 /* Plot up to 3 spectra & wait for key */
140 void xspect_plot(xspect *sp1, xspect *sp2, xspect *sp3);
141 
142 /* Plot up to 10 spectra */
143 void xspect_plot10(xspect *sp, int n);
144 
145 #endif /* !SALONEINSTLIB*/
146 
147 /* ------------------------------------------------------------------------------ */
148 /* Class for converting between spectral and CIE */
149 
150 /* We build in some useful spectra */
151 
152 /* Type of illumination */
153 typedef enum {
154     icxIT_default	 = 0,	/* Default illuminant (usually D50) */
155     icxIT_none		 = 1,	/* No illuminant - self luminous spectrum */
156     icxIT_custom	 = 2,	/* Custom illuminant spectrum */
157     icxIT_A			 = 3,	/* Standard Illuminant A */
158 	icxIT_C          = 4,	/* Standard Illuminant C */
159     icxIT_D50		 = 5,	/* Daylight 5000K */
160     icxIT_D50M2		 = 6,	/* Daylight 5000K, UV filtered (M2) */
161     icxIT_D55		 = 7,	/* Daylight 5500K (use specified temperature) */
162     icxIT_D65		 = 8,	/* Daylight 6500K */
163     icxIT_D75		 = 9,	/* Daylight 7500K (uses specified temperature) */
164     icxIT_E		     = 10,	/* Equal Energy = flat = 1.0 */
165 #ifndef SALONEINSTLIB
166     icxIT_F5		 = 11,	/* Fluorescent, Standard, 6350K, CRI 72 */
167     icxIT_F8		 = 12,	/* Fluorescent, Broad Band 5000K, CRI 95 */
168     icxIT_F10		 = 13,	/* Fluorescent Narrow Band 5000K, CRI 81 */
169 	icxIT_Spectrocam = 14,	/* Spectrocam Xenon Lamp */
170 #endif /* !SALONEINSTLIB*/
171     icxIT_ODtemp	 = 15,	/* Daylight at specified temperature */
172     icxIT_Dtemp		 = 16,	/* 15:2004 Daylight at specified temperature */
173     icxIT_OPtemp     = 17,	/* Planckian at specified temperature */
174     icxIT_Ptemp		 = 18	/* 15:2004 Planckian at specified temperature */
175 } icxIllumeType;
176 
177 /* Fill in an xpsect with a standard illuminant spectrum */
178 /* return 0 on sucecss, nz if not matched */
179 int standardIlluminant(
180 xspect *sp,					/* Xspect to fill in */
181 icxIllumeType ilType,		/* Type of illuminant */
182 double temp);				/* Optional temperature in degrees kelvin, For Dtemp and Ptemp */
183 
184 /* Given an emission spectrum, set the UV output to the given level. */
185 /* The shape of the UV is taken from FWA1_stim, and the level is */
186 /* with respect to the average of the input spectrum. */
187 void xsp_setUV(xspect *out, xspect *in, double uvlevel);
188 
189 
190 /* Type of observer */
191 typedef enum {
192     icxOT_default			= 0,	/* Default observer (usually CIE_1931_2) */
193     icxOT_none			    = 1,	/* No observer - (don't compute XYZ) */
194     icxOT_custom			= 2,	/* Custom observer type weighting */
195     icxOT_CIE_1931_2		= 3,	/* Standard CIE 1931 2 degree */
196     icxOT_CIE_1964_10		= 4,	/* Standard CIE 1964 10 degree */
197 #ifndef SALONEINSTLIB
198     icxOT_Stiles_Burch_2	= 5,	/* Stiles & Burch 1955 2 degree */
199     icxOT_Judd_Voss_2		= 6,	/* Judd & Voss 1978 2 degree */
200     icxOT_CIE_1964_10c		= 7,	/* Standard CIE 1964 10 degree, 2 degree compatible */
201     icxOT_Shaw_Fairchild_2	= 8,	/* Shaw & Fairchild 1997 2 degree */
202     icxOT_EBU_2012	        = 9		/* EBU standard camera curves 2012 */
203 #endif /* !SALONEINSTLIB*/
204 } icxObserverType;
205 
206 /* Return pointers to three xpsects with a standard observer weighting curves */
207 /* return 0 on sucecss, nz if not matched */
208 int standardObserver(xspect *sp[3], icxObserverType obType);
209 
210 /* Return a string describing the standard observer */
211 char *standardObserverDescription(icxObserverType obType);
212 
213 
214 /* Clamping state */
215 typedef enum {
216     icxNoClamp			= 0,	/* Don't clamp XYZ/Lab to +ve */
217     icxClamp			= 1,	/* Clamp XYZ/Lab to +ve */
218 } icxClamping;
219 
220 /* The conversion object */
221 struct _xsp2cie {
222 	/* Private: */
223 	xspect illuminant;			/* Lookup conversion/observer illuminant */
224 	int isemis;					/* nz if we are doing an emission conversion */
225 	xspect observer[3];
226 	int doLab;					/* Return D50 Lab result */
227 	icxClamping clamp;			/* Clamp XYZ and Lab to be +ve */
228 
229 	/* Integration range and steps - set to observer range and 1nm by default.  */
230 	int    spec_bw;				/* Integration bandwidth (nm) */
231 	double spec_wl_short;		/* Start wavelength (nm) */
232 	double spec_wl_long;		/* End wavelength (nm) */
233 
234 #ifndef SALONEINSTLIB
235 	/* FWA compensation */
236 	double fwa_bw;	/* Integration bandwidth */
237 	xspect iillum;	/* Y = 1 Normalised instrument illuminant spectrum */
238 	xspect imedia;	/* Instrument measured media */
239 	xspect emits;	/* Estimated FWA emmission spectrum */
240 	xspect media;	/* Estimated base media (ie. minus FWA) */
241 	xspect tillum;	/* Y = 1 Normalised target/simulated instrument illuminant spectrum */
242 					/* Use oillum if tillum spec_n = 0 */
243 	xspect oillum;	/* Y = 1 Normalised observer illuminant spectrum */
244 	double Sm;		/* FWA Stimulation level for emits contribution */
245 	double FWAc;	/* FWA content (informational) */
246 	int    insteqtarget;	/* iillum == tillum, bypass FWA */
247 #endif /* !SALONEINSTLIB*/
248 
249 	/* Public: */
250 	void (*del)(struct _xsp2cie *p);
251 
252 	/* Override the integration wavelength range and step size */
253 	void (*set_int_steps)(struct _xsp2cie *p,	/* this */
254 	                      double bw,		/* Integration step size (nm) */
255 	                      double shortwl,	/* Starting nm */
256 	                      double longwl		/* Ending nm */
257 	                     );
258 
259 	/* Convert (and possibly fwa correct) reflectance spectrum */
260 	/* Note that the input spectrum normalisation value is used. */
261 	/* Note that the returned XYZ is 0..1 range for reflectanc. */
262 	/* Emissive spectral values are assumed to be in mW/nm, and sampled */
263 	/* rather than integrated if they are not at 1nm spacing. */
264 	void (*convert) (struct _xsp2cie *p,	/* this */
265 	                 double *out,			/* Return XYZ or D50 Lab value */
266 	                 xspect *in				/* Spectrum to be converted, normalised by norm */
267 	                );
268 
269 	/* Convert and also return (possibly corrected) reflectance spectrum */
270 	/* Spectrum will be same wlength range and readings as input spectrum */
271 	/* Note that the returned XYZ is 0..1 range for reflectanc. */
272 	/* Emissive spectral values are assumed to be in mW/nm, and sampled */
273 	/* rather than integrated if they are not at 1nm spacing. */
274 	void (*sconvert) (struct _xsp2cie *p,	/* this */
275 	                 xspect *sout,			/* Return corrected refl. spectrum (may be NULL) */
276 	                 double *out,			/* Return XYZ or D50 Lab value (may be NULL) */
277 	                 xspect *in				/* Spectrum to be converted, normalised by norm */
278 	                );
279 
280 	/* Get the XYZ of the illuminant being used to compute the CIE XYZ */
281 	/* value. */
282 	void (*get_cie_il)(struct _xsp2cie *p,	/* this */
283 	                   double *xyz			/* Return the XYZ */
284 	                   );
285 
286 #ifndef SALONEINSTLIB
287 	/* Set Fluorescent Whitening Agent compensation */
288 	/* return NZ if error */
289 	int (*set_fwa) (struct _xsp2cie *p,	/* this */
290 					xspect *iillum,		/* Spectrum of instrument illuminant */
291 					xspect *tillum,		/* Spectrum of target/simulated instrument illuminant, */
292 										/* NULL to use observer illuminant. */
293 	                xspect *white		/* Spectrum of plain media */
294 	                );
295 
296 	/* Set FWA given updated conversion illuminants. */
297 	/* (We assume that xsp2cie_set_fwa has been called first) */
298 	/* return NZ if error */
299 	int (*update_fwa_custillum) (struct _xsp2cie *p,
300 					xspect *tillum,		/* Spectrum of target/simulated instrument illuminant, */
301 										/* NULL to use set_fwa() value. */
302 	                xspect *custIllum	/* Spectrum of observer illuminant */
303 										/* NULL to use new_xsp2cie() value. */
304 	                );
305 
306 	/* Get Fluorescent Whitening Agent compensation information */
307 	/* return NZ if error */
308 	void (*get_fwa_info) (struct _xsp2cie *p,	/* this */
309 					double *FWAc		/* FWA content as a ratio. */
310 	                );
311 
312 
313 	/* Set Media White. This enables extracting and applying the */
314 	/* colorant reflectance value from/to the meadia. */
315 	/* return NZ if error */
316 	int (*set_mw) (struct _xsp2cie *p,	/* this */
317 	                xspect *white		/* Spectrum of plain media */
318 	                );
319 
320 	/* Extract the colorant reflectance value from the media. Takes FWA */
321 	/* into account if set. Media white or FWA must be set. */
322 	/* return NZ if error */
323 	int (*extract) (struct _xsp2cie *p,	/* this */
324 	                 xspect *out,			/* Extracted colorant refl. spectrum */
325 	                 xspect *in				/* Spectrum to be converted, normalised by norm */
326 	                );
327 
328 
329 	/* Apply the colorant reflectance value from the media. Takes FWA */
330 	/* into account if set. DOESN'T convert to FWA target illumination! */
331 	/* FWA must be set. */
332 	int (*apply) (struct _xsp2cie *p,	/* this */
333 	                 xspect *out,			/* Applied refl. spectrum */
334 	                 xspect *in				/* Colorant reflectance to be applied */
335 	                );
336 #endif /* !SALONEINSTLIB*/
337 
338 }; typedef struct _xsp2cie xsp2cie;
339 
340 xsp2cie *new_xsp2cie(
341 	icxIllumeType ilType,			/* Observer Illuminant to use */
342 	xspect        *custIllum,		/* Custom illuminant if ilType == icxIT_custom */
343 
344 	icxObserverType obType,			/* Observer */
345 	xspect        custObserver[3],	/* Custom observer if obType == icxOT_custom */
346 	icColorSpaceSignature  rcs,		/* Return color space, icSigXYZData or D50 icSigLabData */
347 									/* ** Must be icSigXYZData if SALONEINSTLIB ** */
348 	icxClamping clamp				/* NZ to clamp XYZ/Lab to be +ve */
349 );
350 
351 #ifndef SALONEINSTLIB
352 
353 /* --------------------------- */
354 /* Given a choice of temperature dependent illuminant (icxIT_[O]Dtemp or icxIT_[O]Ptemp), */
355 /* return the closest correlated color temperature to the XYZ. */
356 /* An observer type can be chosen for interpretting the spectrum of the input and */
357 /* the illuminant. */
358 /* Return -1.0 on erorr */
359 /* (Faster, slightly less accurate version of icx_XYZ2ill_ct()) */
360 double icx_XYZ2ill_ct2(
361 double txyz[3],			/* If not NULL, return the XYZ of the locus temperature */
362 icxIllumeType ilType,	/* Type of illuminant, icxIT_[O]Dtemp or icxIT_[O]Ptemp */
363 icxObserverType obType,	/* Observer, CIE_1931_2 or CIE_1964_10 */
364 double xyz[3],			/* Input XYZ value */
365 int viscct				/* nz to use visual CIEDE2000, 0 to use CCT CIE 1960 UCS. */
366 );
367 
368 /* Given a choice of temperature dependent illuminant (icxIT_[O]Dtemp or icxIT_[O]Ptemp), */
369 /* a color temperature and a Y value, return the corresponding XYZ */
370 /* An observer type can be chosen for interpretting the spectrum of the input and */
371 /* the illuminant. */
372 /* Return xyz[0] = -1.0 on erorr */
373 /* (Faster, slightly less accrurate alternative to standardIlluminant()) */
374 void icx_ill_ct2XYZ(
375 double xyz[3],			/* Return the XYZ value */
376 icxIllumeType ilType,	/* Type of illuminant, icxIT_[O]Dtemp or icx[O]IT_Ptemp */
377 icxObserverType obType,	/* Observer, CIE_1931_2 or CIE_1964_10 */
378 int viscct,				/* nz to use visual CIEDE2000, 0 to use CCT CIE 1960 UCS. */
379 double tin,				/* Input temperature */
380 double Yin				/* Input Y value */
381 );
382 
383 /* --------------------------- */
384 /* Spectrum locus              */
385 
386 /* Return the spectrum locus range for the given observer. */
387 /* return 0 on sucecss, nz if observer not known */
388 int icx_spectrum_locus_range(double *min_wl, double *max_wl, icxObserverType obType);
389 
390 /* Return an XYZ that is on the spectrum locus for the given observer. */
391 /* wl is the input wavelength in the range icx_chrom_locus_range(), */
392 /* and return clipped result if outside this range. */
393 /* Return nz if observer unknown. */
394 int icx_spectrum_locus(double xyz[3], double in, icxObserverType obType);
395 
396 /* - - - - - - - - - - - - - - */
397 /* Chromaticity locus support */
398 
399 typedef struct _xslpoly xslpoly;
400 
401 typedef enum {
402     icxLT_none	     = 0,
403     icxLT_spectral	 = 1,
404     icxLT_daylight	 = 2,
405     icxLT_plankian	 = 3
406 } icxLocusType;
407 
408 /* Return a pointer to the (static) chromaticity locus object */
409 /* return NULL on failure. */
410 xslpoly *chrom_locus_poligon(icxLocusType locus_type, icxObserverType obType, int cspace);
411 
412 
413 /* Determine whether the given XYZ is outside the chromaticity locus */
414 /* Return 0 if within locus */
415 /* Return 1 if outside locus */
416 int icx_outside_spec_locus(xslpoly *p, double xyz[3]);
417 
418 /* ------------------------------------------------- */
419 
420 /* Given a reflectance/transmittance spectrum, */
421 /* an illuminant definition and an observer model, return */
422 /* the XYZ value for that spectrum. */
423 /* Return 0 on sucess, 1 on error */
424 /* (One shot version of xsp2cie etc.) */
425 int icx_sp2XYZ(
426 double xyz[3],			/* Return XYZ value */
427 icxObserverType obType,	/* Observer */
428 xspect custObserver[3],	/* Optional custom observer */
429 icxIllumeType ilType,	/* Type of illuminant, icxIT_[O]Dtemp or icxIT_[O]Ptemp */
430 double ct,				/* Input temperature in degrees K */
431 xspect *custIllum,		/* Optional custom illuminant */
432 xspect *sp				/* Spectrum to be converted */
433 );
434 
435 /* ------------------------------------------------- */
436 /* Color temperature and CRI */
437 
438 /* Given an illuminant definition and an observer model, return */
439 /* the normalised XYZ value for that spectrum. */
440 /* Return 0 on sucess, 1 on error */
441 /* (One shot version of xsp2cie etc.) */
442 int icx_ill_sp2XYZ(
443 double xyz[3],			/* Return XYZ value with Y == 1 */
444 icxObserverType obType,	/* Observer */
445 xspect custObserver[3],	/* Optional custom observer */
446 icxIllumeType ilType,	/* Type of illuminant */
447 double temp,			/* Input temperature in degrees K */
448 xspect *custIllum);		/* Optional custom illuminant */
449 
450 /* Given a choice of temperature dependent illuminant (icxIT_[O]Dtemp or icxIT_[O]Ptemp), */
451 /* return the closest correlated color temperature to the given spectrum or XYZ. */
452 /* An observer type can be chosen for interpretting the spectrum of the input and */
453 /* the illuminant. */
454 /* Return -1 on erorr */
455 double icx_XYZ2ill_ct(
456 double txyz[3],			/* If not NULL, return the XYZ of the black body temperature */
457 icxIllumeType ilType,	/* Type of illuminant, icxIT_[O]Dtemp or icxIT_[O]Ptemp */
458 icxObserverType obType,	/* Observer */
459 xspect custObserver[3],	/* Optional custom observer */
460 double xyz[3],			/* Input XYZ value, NULL if spectrum intead */
461 xspect *insp0,			/* Input spectrum value, NULL if xyz[] instead */
462 int viscct);			/* nz to use visual CIEDE2000, 0 to use CCT CIE 1960 UCS. */
463 
464 /* Compute the CIE1995 CRI: Ra */
465 /* Return < 0.0 on error */
466 /* If invalid is not NULL, set it to nz if CRI */
467 /* is invalid because the sample is not white enough. */
468 double icx_CIE1995_CRI(
469 int *invalid,			/* if not NULL, set to nz if invalid */
470 double cris[14],		/* If not NULL, return the TCS01-14 CRI's */
471 xspect *sample			/* Illuminant sample to compute CRI of */
472 );
473 
474 /* Compute the EBU TLCI-2012 Qa */
475 /* Return < 0.0 on error */
476 /* If invalid is not NULL, set it to nz if TLCI */
477 /* is invalid because the sample is not white enough. */
478 double icx_EBU2012_TLCI(
479 int *invalid,			/* if not NULL, set to nz if invalid */
480 xspect *sample			/* Illuminant sample to compute TLCI of */
481 );
482 
483 /* Return the maximum 24 hour exposure in seconds. */
484 /* Limit is 8 hours */
485 /* Returns -1 if the source sample doesn't go down to at least 350 nm */
486 double icx_ARPANSA_UV_exp(
487 xspect *sample			/* Illuminant sample to compute UV_exp of */
488 );
489 
490 /* Return a polinomial aproximation of CCT */
491 double aprox_CCT(double xyz[3]);
492 
493 /* Aproximate x,y from CCT using Kim et al's cubic spline. */
494 /* Invalid < 1667 and > 25000 */
495 /* (Doesn't set Yxy[0]) */
496 void aprox_plankian(double Yxy[3], double ct);
497 
498 /* --------------------------- */
499 /* Density and other functions */
500 
501 /* Given a reflectance or transmition spectral product, */
502 /* return status T CMY + V density values */
503 void xsp_Tdensity(double *out,			/* Return CMYV density */
504                  xspect *in				/* Spectral product to be converted */
505                 );
506 
507 /* Given a reflectance or transmission XYZ value, */
508 /* return approximate status T CMYV log10 density values */
509 void icx_XYZ2Tdens(
510 double *out,			/* Return aproximate CMYV log10 density */
511 double *in				/* Input XYZ values */
512 );
513 
514 /* Given a reflectance or transmission XYZ value, */
515 /* return log10 XYZ density values */
516 void icx_XYZ2dens(
517 double *out,			/* Return log10 XYZ density */
518 double *in				/* Input XYZ values */
519 );
520 
521 /* Given an XYZ value, */
522 /* return sRGB values */
523 void icx_XYZ2sRGB(
524 double *out,			/* Return sRGB value */
525 double *wp,				/* Input XYZ white point (D65 used if NULL) */
526 double *in				/* Input XYZ values */
527 );
528 
529 /* Given an RGB value, return XYZ values. */
530 /* This is a little slow */
531 void icx_sRGB2XYZ(
532 double *out,			/* Return XYZ values */
533 double *wp,				/* Output XYZ white point (D65 used if NULL) */
534 double *in				/* Input sRGB values */
535 );
536 
537 /* Given an XYZ value, return approximate RGB value */
538 /* Desaurate to white by the given amount */
539 void icx_XYZ2RGB_ds(
540 double *out,			/* Return approximate sRGB values */
541 double *in,				/* Input XYZ */
542 double desat			/* 0.0 = full saturation, 1.0 = white */
543 );
544 
545 /* Given a wavelengthm return approximate RGB value */
546 /* Desaurate to white by the given amount */
547 void icx_wl2RGB_ds(
548 double *out,			/* Return approximate sRGB values */
549 double wl,				/* Input wavelength in nm */
550 double desat			/* 0.0 = full saturation, 1.0 = white */
551 );
552 
553 
554 #endif /* !SALONEINSTLIB*/
555 
556 #ifdef __cplusplus
557 	}
558 #endif
559 
560 #endif /* XSPECTFM_H */
561 
562 
563 
564 
565 
566 
567 
568 
569 
570 
571 
572 
573 
574 
575 
576 
577 
578 
579 
580 
581 
582 
583 
584 
585 
586 
587 
588 
589 
590 
591 
592 
593 
594 
595 
596 
597 
598 
599