The following functions compute colors from spectra, scale color luminance, and extract chromaticity. XYZ is used in the names of procedures for unnormalized colors; the coordinates of CIEXYZ colors are constrained as described in Color Spaces.

`(require 'color-space)`

A spectrum may be represented as:

- A procedure of one argument accepting real numbers from 380e-9 to 780e-9, the wavelength in meters; or
- A vector of real numbers representing intensity samples evenly spaced over some range of wavelengths overlapping the range 380e-9 to 780e-9.

CIEXYZ values are calculated as dot-product with the X, Y (Luminance),
and Z Spectral Tristimulus Values. The files `cie1931.xyz`
and `cie1964.xyz` in the distribution contain these CIE-defined
values.

— Feature: **cie1964**

Loads the Spectral Tristimulus Values CIE 1964 Supplementary Standard Colorimetric Observer, defining

cie:x-bar,cie:y-bar, andcie:z-bar.

— Feature: **cie1931**

Loads the Spectral Tristimulus Values CIE 1931 Supplementary Standard Colorimetric Observer, defining

cie:x-bar,cie:y-bar, andcie:z-bar.

— Feature: **ciexyz**

Requires Spectral Tristimulus Values, defaulting to cie1931, defining

cie:x-bar,cie:y-bar, andcie:z-bar.

`(require 'cie1964)`

or `(require 'cie1931)`

will
`load-ciexyz`

specific values used by the following spectrum
conversion procedures. The spectrum conversion procedures
`(require 'ciexyz)`

to assure that a set is loaded.

— Function: **read-cie-illuminant**` path`

pathmust be a string naming a file consisting of 107 numbers for 5.nm intervals from 300.nm to 830.nm.`read-cie-illuminant`

reads (using Scheme`read`

) these numbers and returns a length 107 vector filled with them.

(define CIE:SI-D65 (read-CIE-illuminant (in-vicinity (library-vicinity) "ciesid65.dat"))) (spectrum->XYZ CIE:SI-D65 300e-9 830e-9) ⇒ (25.108569422374994 26.418013465625001 28.764075683374993)

— Function: **read-normalized-illuminant**` path`

pathmust be a string naming a file consisting of 107 numbers for 5.nm intervals from 300.nm to 830.nm.`read-normalized-illuminant`

reads (using Scheme`read`

) these numbers and returns a length 107 vector filled with them, normalized so that`spectrum->XYZ`

of the illuminant returns its whitepoint.

CIE Standard Illuminants A and D65 are included with SLIB:

(define CIE:SI-A (read-normalized-illuminant (in-vicinity (library-vicinity) "ciesia.dat"))) (define CIE:SI-D65 (read-normalized-illuminant (in-vicinity (library-vicinity) "ciesid65.dat"))) (spectrum->XYZ CIE:SI-A 300e-9 830e-9) ⇒ (1.098499460820401 999.9999999999998e-3 355.8173930654951e-3) (CIEXYZ->sRGB (spectrum->XYZ CIE:SI-A 300e-9 830e-9)) ⇒ (255 234 133) (spectrum->XYZ CIE:SI-D65 300e-9 830e-9) ⇒ (950.4336673552745e-3 1.0000000000000002 1.0888053986649182) (CIEXYZ->sRGB (spectrum->XYZ CIE:SI-D65 300e-9 830e-9)) ⇒ (255 255 255)

— Function: **illuminant-map**` proc siv`

sivmust be a one-dimensional array or vector of 107 numbers.`illuminant-map`

returns a vector of length 107 containing the result of applyingprocto each element ofsiv.

— Function: **spectrum->XYZ**` proc`

procmust be a function of one argument.`spectrum->XYZ`

computes the CIEXYZ(1931) values for the spectrum returned byprocwhen called with arguments from 380e-9 to 780e-9, the wavelength in meters.

— Function: **spectrum->XYZ**` spectrum x1 x2`

x1andx2must be positive real numbers specifying the wavelengths (in meters) corresponding to the zeroth and last elements of vector or listspectrum.`spectrum->XYZ`

returns the CIEXYZ(1931) values for a light source with spectral values proportional to the elements ofspectrumat evenly spaced wavelengths betweenx1andx2.Compute the colors of 6500.K and 5000.K blackbody radiation:

(require 'color-space) (define xyz (spectrum->XYZ (blackbody-spectrum 6500))) (define y_n (cadr xyz)) (map (lambda (x) (/ x y_n)) xyz) ⇒ (0.9687111145512467 1.0 1.1210875945303613) (define xyz (spectrum->XYZ (blackbody-spectrum 5000))) (map (lambda (x) (/ x y_n)) xyz) ⇒ (0.2933441826889158 0.2988931825387761 0.25783646831201573)

— Function: **spectrum->chromaticity**` proc`

— Function:**spectrum->chromaticity**` spectrum x1 x2`

— Function:

Computes the chromaticity for the given spectrum.

— Function: **wavelength->XYZ**` w`

wmust be a number between 380e-9 to 780e-9.`wavelength->XYZ`

returns (unnormalized) XYZ values for a monochromatic light source with wavelengthw.

— Function: **wavelength->chromaticity**` w`

wmust be a number between 380e-9 to 780e-9.`wavelength->chromaticity`

returns the chromaticity for a monochromatic light source with wavelengthw.

— Function: **blackbody-spectrum**` temp`

— Function:**blackbody-spectrum**` temp span`

— Function:

Returns a procedure of one argument (wavelength in meters), which returns the radiance of a black body at

temp.The optional argument

spanis the wavelength analog of bandwidth. With the defaultspanof 1.nm (1e-9.m), the values returned by the procedure correspond to the power of the photons with wavelengthswtow+1e-9.

— Function: **temperature->XYZ**` x`

The positive number

xis a temperature in degrees kelvin.`temperature->XYZ`

computes the unnormalized CIEXYZ(1931) values for the spectrum of a black body at temperaturex.Compute the chromaticities of 6500.K and 5000.K blackbody radiation:

(require 'color-space) (XYZ->chromaticity (temperature->XYZ 6500)) ⇒ (0.3135191660557008 0.3236456786200268) (XYZ->chromaticity (temperature->XYZ 5000)) ⇒ (0.34508082841161052 0.3516084965163377)

— Function: **temperature->chromaticity**` x`

The positive number

xis a temperature in degrees kelvin.`temperature->cromaticity`

computes the chromaticity for the spectrum of a black body at temperaturex.Compute the chromaticities of 6500.K and 5000.K blackbody radiation:

(require 'color-space) (temperature->chromaticity 6500) ⇒ (0.3135191660557008 0.3236456786200268) (temperature->chromaticity 5000) ⇒ (0.34508082841161052 0.3516084965163377)

— Function: **XYZ->chromaticity**` xyz`

Returns a two element list: the x and y components of

xyznormalized to 1 (=x+y+z).

— Function: **chromaticity->whitepoint**` x y`

Returns the CIEXYZ(1931) values having luminosity 1 and chromaticity

xandy.

Many color datasets are expressed in xyY format; chromaticity with CIE luminance (Y). But xyY is not a CIE standard like CIEXYZ, CIELAB, and CIELUV. Although chrominance is well defined, the luminance component is sometimes scaled to 1, sometimes to 100, but usually has no obvious range. With no given whitepoint, the only reasonable course is to ascertain the luminance range of a dataset and normalize the values to lie from 0 to 1.

— Function: **XYZ->xyY**` xyz`

Returns a three element list: the

xandycomponents ofXYZnormalized to 1, and CIE luminanceY.

— Function: **xyY:normalize-colors**` colors`

colorsis a list of xyY triples.`xyY:normalize-colors`

scales each chromaticity so it sums to 1 or less; and divides theYvalues by the maximumYin the dataset, so all lie between 0 and 1.

— Function: **xyY:normalize-colors**` colors n`

If

nis positive real, then`xyY:normalize-colors`

divides theYvalues byntimes the maximumYin the dataset.If

nis an exact non-positive integer, then`xyY:normalize-colors`

divides theYvalues by the maximum of theYs in the dataset excepting the -nlargestYvalues.In all cases, returned

Yvalues are limited to lie from 0 to 1.

Why would one want to normalize to other than 1? If the sun or its reflection is the brightest object in a scene, then normalizing to its luminance will tend to make the rest of the scene very dark. As with photographs, limiting the specular highlights looks better than darkening everything else.

The results of measurements being what they are,
`xyY:normalize-colors`

is extremely tolerant. Negative numbers are
replaced with zero, and chromaticities with sums greater than one are
scaled to sum to one.