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 20143 days, 9 hours, 56 minutes ago.