Illuminants

To see — and in specific to see color — we need light. During the day, when outdoors, that light is produced by the sun. In the evening light is mostly produced by electric lamps, such as incandescent, fluorescent, or LED lamps. How we see color depends on the way the objects around us are illuminated, and illuminants play an important role in colorimetry. You might have experienced “bad lighting” yourself, when buying clothes in a store, for example, and noticed that the colors of a shirt look quite different outdoors than how they looked in the store.

In colorimetry, an illuminant represents the spectral power distribution of the light illuminating an object. Typically, in colorimetric modeling, a single source of light is used, such as daylight, light from a fluorescent lamp, or LED lamps for newer installations.

The Toolbox contains mathematical illuminants, such as Blackbody, which uses Planck’s equation to calculate a spectral distribution, and illuminants represented by an array of data, which are available on this site in form of JSON data files.

All illuminants in this library implement the illuminate method, which takes a wavelength domain as an argument, and will produce an array of 64-bit floating point numbers in form of a Float64Array-type. They also implement a domain method, which produces the native wavelength domain for the data in the illuminant, or results in an undefined type, when the data has no inherent or native domain. This is for example the case with function model data, such as the Blackbody illuminant which is based on Planck’s law, or the Led illuminant, which is using a Gaussian type of function to calculate spectral distribution.

Here is an example of a Blackbody illuminant, with a color temperature of 3000K, which spectral power distribution is obtained by:

    // deno run --allow-net examples/illuminants/introduction/bb.ts
    import init, { Blackbody, Domain } from "https://www.gerardharbers.com/cie.js";
    await init();

    // create a blackbody illuminant with a color temperature of 3000K
    const bb3000 = new Blackbody(3000.0)

    // get its spectral power distribution in 256 points, 
    // over a wavelength range from 0.3 to 3 micrometer
    const domain = new Domain(0.3E-6, 3E-6, 256);
    const spd = bb3000.illuminate(domain);

    // print first 5 values
    console.log(spd.slice(0,5).map(v=>+v.toFixed(2)));

    /*
     Output:
        Float64Array(5) [ 3824.39, 5545.37, 7802.22, 10684.53, 14279.18 ]
    */

Notice the --allow-net option in Deno, which is required as the program will load the Cie-library online. The Blackbody illuminant is based on a mathematical model and is implemented and contained within the Cie-library.

Besides model-based illuminants, the library also has a large collection of illuminants directly defined by data. Typically these are measured directly, or derived from measured data. These illuminants are pulled into the library as a DataIlluminant, using its fetch method:

    // deno run --allow-net examples/illuminants/introduction/d65.ts
    import init, {
        DataIlluminant, 
        fetchD65, 
        Domain 
    } from "https://www.gerardharbers.com/cie.js";
    await init();

    // Get D65 illuminant using the DataIlluminant directly
    let d65 = await DataIlluminant.fetch("cie/d65.json");

    // or use a convenience constructor function
    d65 = await fetchD65();

    // get the CIE D65 spectral values as in the datafile, 
    // which has a range from 300 to 780 nm, and an interval of 5nm (97 points):
    const native_domain = d65.domain() as Domain;
    const _spd = d65.illuminate(native_domain);

    // to get data for another domain, 
    // for example for a wavelength range from 380 to 780nm,
    // using an interval of 1nm (401 points):
    const spd_1nm = d65.illuminate(new Domain(380E-9, 780E-9, 401));

    // print first 5 values
    console.log(spd_1nm.slice(0,5).map(v=>+v.toFixed(2)));

    // Output: Float64Array(5) [ 49.98, 50.44, 50.91, 51.38, 51.84 ]

The data is contained in JSON files, and located on the same server as this site. To fetch these data-based illuminants, you have to use the await keyword, as they are fetched from the server asynchronously. In this library, all the functions and methods containing the word fetch need the await keyword, and if used in a function you write, it requires the keyword async too. When these async functions are invocated, they also need the await keyword. For example:

    // deno run --allow-net examples/illuminants/introduction/printd65.ts

    import init, {fetchD65, Domain } from "https://www.gerardharbers.com/cie.js";
    await init();

    async function d65Values() {
        const d65 = await fetchD65();
        return d65.illuminate(new Domain(380E-9, 780E-9, 21));
    }

    // use await keyword here
    const spd_20nm = await d65Values();
    console.log(spd_20nm.map(v=>+v.toFixed(2)));

    /*
    Output: 
        Float64Array(21) [
            49.98,  82.75,  93.43, 104.87, 117.81, 115.92, 109.35, 104.79,
            104.4,    100,  95.79,  90.01, 87.7,   83.7,  80.21,  78.28,
            71.61,   61.6,  75.09,  46.42, 63.38
        ]
    */

The library has the following illuminants and illuminant libraries (for details see the later sections in this chapter):

  • Illuminant Blackbody, using Planck’s law to calculate the spectral emission of a blackbody for a given temperature.

        import init, {Blackbody} from "https://www.gerardharbers.com/cie.js";
        await init();
        const bb3000 = new Blackbody(3000.0);
    
  • CIE Standard D illuminant, for correlated color temperatures in the range from 4000 to 25000K:

        import init, {Daylight} from "https://www.gerardharbers.com/cie.js";
        await init();
        const d5000 = new Daylight(5000.0);
    
  • CIE Standard Data Illuminants C, D50, D55, D65, D75, F1 to F12, F3.1 to F3.15, HP1 to HP5, and LED series. For example, to get the CIE LED-B1 and the CIE F3.1 standard illuminants, use fetchLED_B1 and fetchF3_1:

        import init, {
            fetchLED_B1, fetchF3_1
            } from "https://www.gerardharbers.com/cie.js";
        await init();
        const ledB1 = await fetchLED_B1();
        const f31 = await fetchF3_1();
    
  • The IES TM30 illuminant collection is available in the library too. This is a collection of 318 illuminants, all defined as data illuminants in the range from 380 to 780nm with 1nm steps. This collection was used to test and optimize the TM30 and CIE color fidelity metrics. The individual illuminants can be obtained directly, using their ordinal number as listed in the TM30 Excel sheet:

        import init, {DataIlluminant} from "https://www.gerardharbers.com/cie.js";
        await init();
        
        // get the first illuminant in this series, which is the CIE F1 illuminant;
        const f1 = await DataIlluminant.fetch("tm30lib/tm30lib001.json");
    
        // illuminant 50 is a measured example of the F40T12/41U Fluorescent lamp:
        const f40t12 = await DataIlluminant.fetch("tm30lib/tm30lib050.json");
    
        // get the last illuminant in this series, "Tri-band Gaussian [2)", 
        // an example of a theoretical illuminant using
        // Gaussian shaped compoents
        const tribandGauss2 = await DataIlluminant.fetch("tm30lib/tm30lib318.json");
    

    Due to the size of this collection, it is also possible to search for illuminant emission types and categories, using the IlluminantsLib class methods. See for more information in the TM30 Illuminants Example library section.

  • A generic LED Array Illuminant,