Download or view colorspace.frink in plain text format
/** This file contains functions for converting between colorspaces.
See:
Converting light frequency to RGB:
https://stackoverflow.com/questions/1472514/convert-light-frequency-to-rgb
Simple Analytic Approximations to the CIE XYZ Color Matching Functions:
https://jcgt.org/published/0002/02/01/
CIE 1931 color space:
https://en.wikipedia.org/wiki/CIE_1931_color_space
http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html
*/
/** A multi-lobe, piecewise Gaussian fit of CIE 1931 XYZ Color Matching
Functions by Wyman el al. The code is adopted from the Listing 1 (eq. 4) of
Chris Wyman, Peter-Pike Sloan, and Peter Shirley, Simple Analytic
Approximations to the CIE XYZ Color Matching Functions,
Journal of Computer Graphics Techniques (JCGT), vol. 2, no. 2, 1-11, 2013.
https://jcgt.org/published/0002/02/01/
returns:
[X, Y, Z]
*/
wavelengthToXYZ[wavelength is length] :=
{
wave = wavelength / nm
t1x = (wave - 442.0) * ((wave < 442.0) ? 0.0624 : 0.0374)
t2x = (wave - 599.8) * ((wave < 599.8) ? 0.0264 : 0.0323)
t3x = (wave - 501.1) * ((wave < 501.1) ? 0.0490 : 0.0382)
x = 0.362 * exp[-0.5 t1x^2] +
1.056 * exp[-0.5 t2x^2] -
0.065 * exp[-0.5 t3x^2]
t1y = (wave - 568.8) * ((wave < 568.8) ? 0.0213 : 0.0247)
t2y = (wave - 530.9) * ((wave < 530.9) ? 0.0613 : 0.0322)
y = 0.821 * exp[-0.5 t1y^2] + 0.286 * exp[-0.5 t2y^2]
t1z = (wave - 437.0) * ((wave < 437.0) ? 0.0845 : 0.0278)
t2z = (wave - 459.0) * ((wave < 459.0) ? 0.0385 : 0.0725)
z = 1.217 * exp[-0.5 t1z^2] + 0.681 * exp[-0.5 t2z^2]
return [x,y,z]
}
/** Convert a wavelength to an RGB color in the sRGB space.
returns:
[R, G, B]
*/
wavelengthToRGB[wavelength is length] :=
{
XYZ = wavelengthToXYZ[wavelength]
return XYZtoRGB[XYZ]
}
/** Convert a color in the XYZ space to the sRGB color space. The conversion
matrix and color component transfer function is taken from
http://www.color.org/srgb.pdf
and
http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html
which follows the International Electrotechnical Commission standard
IEC 61966-2-1 "Multimedia systems and equipment - Colour measurement and
management - Part 2-1: Colour management - Default RGB colour space - sRGB"
arguments:
XYZ: an array containing the XYZ components from 0 to 1 [X, Y, Z]
returns an array:
[R, G, B]
*/
XYZtoRGB[XYZ] :=
{
[x, y, z] = XYZ
rl = 3.2406255 x + -1.537208 y + -0.4986286 z
gl = -0.9689307 x + 1.8757561 y + 0.0415175 z
bl = 0.0557101 x + -0.2040211 y + 1.0569959 z
// TODO: Clamp output components from 0 to 1?
return [postProcessXYZ[rl],
postProcessXYZ[gl],
postProcessXYZ[bl]]
}
/** Apply color component transfer function for the above function. */
postProcessXYZ[c] :=
{
c = clamp[c, 0, 1]
return (c <= 0.0031308 ? 12.92 c : 1.055 c^(1/2.4) - 0.055)
}
/** Convert a color in the sRGB space to the XYZ space. The conversion
matrix and color component transfer function is taken from
http://www.color.org/srgb.pdf
and
http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html
which follows the International Electrotechnical Commission standard
IEC 61966-2-1 "Multimedia systems and equipment - Colour measurement and
management - Part 2-1: Colour management - Default RGB colour space - sRGB"
arguments:
RGB: an array containing the RGB components from 0 to 1 [R, G, B]
returns:
[X, Y, Z]
*/
RGBtoXYZ[RGB] :=
{
[R, G, B] = RGB
rl = preprocessRGB[R]
gl = preprocessRGB[G]
bl = preprocessRGB[B]
X = 0.4124564 rl + 0.3575761 gl + 0.1804375 bl
Y = 0.2126729 rl + 0.7151522 gl + 0.0721750 bl
Z = 0.0193339 rl + 0.1191920 gl + 0.9503041 bl
// TODO: Clamp each channel between 0 and 1?
return [X, Y, Z]
}
/** Perform inverse sRGB companding. See:
http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html
*/
preprocessRGB[V] :=
{
V = clamp[V, 0, 1]
if V <= 0.04045
return V / 12.92
else
return ((V + 0.055) / 1.055)^2.4
}
/** Test function to plot wavelengths */
plotWavelengths[] :=
{
gr = new graphics
gr.backgroundColor[0,0,0]
rl = new polyline
gl = new polyline
bl = new polyline
g2 = new graphics
g2.backgroundColor[0,0,0]
g2.antialiased[false]
stepsize = 1 nm
for lambda = 375 nm to 725 nm step stepsize
{
[r,g,b] = wavelengthToRGB[lambda]
rl.addPoint[lambda/nm/100, -r]
gl.addPoint[lambda/nm/100, -g]
bl.addPoint[lambda/nm/100, -b]
g2.color[clamp[r,0,1],clamp[g,0,1],clamp[b,0,1]]
g2.fillRectCenter[lambda/nm/10, 0, stepsize/nm/10, 10]
println[format[lambda, "nm", 0] + "\t" + format[wavelengthToRGB[lambda], 1, 5]]
}
gr.color[1,0,0]
gr.add[rl]
gr.color[0,1,0]
gr.add[gl]
gr.color[0,0,1]
gr.add[bl]
gr.show[]
g2.show[]
}
Download or view colorspace.frink in plain text format
This is a program written in the programming language Frink.
For more information, view the Frink
Documentation or see More Sample Frink Programs.
Alan Eliasen was born 20217 days, 23 hours, 57 minutes ago.