XYZ to RGB
Given an XYZ color whose components are in the nominal range [0.0, 1.0] and whose reference white is the same as
that of the RGB system, the conversion to companded RGB is done in two steps.
1. XYZ to Linear RGB
$$\left[ \matrix{r \\ g \\ b} \right] = {[M]^{-1}} \left[ \matrix{X \\ Y \\ Z}\right]$$
This gives linear RGB, [rgb].
2. Companding
The linear RGB channels (denoted with lower case $(r, g, b)$, or generically $v$) are made nonlinear (denoted with upper case $(R, G, B)$, or generically $V$).
$$v \in \{r, g, b\}$$
$$V \in \{R, G, B\}$$
The same operation is performed on all three channels, but the operation depends on the companding function associated with the RGB color system.
Gamma Companding
$$V = v^{1/\gamma}$$
sRGB Companding
$$V = \cases{
12.92 v & \text{if }v \leq 0.0031308 \\
1.055 v^{1/2.4} - 0.055 & \text{otherwise}
}$$
L* Companding
$$V = \cases{
{{v \kappa} \over {100}} & \text{if }v \leq \epsilon \\
1.16 \sqrt[3]{v} - 0.16 & \text{otherwise}
}$$
$$\epsilon = \cases{
{0.008856} & \text{Actual CIE standard} \\
{216 / 24389} & \text{Intent of the CIE standard}
}$$
$$\kappa = \cases{
{903.3} & \text{Actual CIE standard} \\
{24389 / 27} & \text{Intent of the CIE standard}
}$$
Implementation Notes:
- The transformation matrix $[M]$ is calculated from the RGB reference primaries as discussed here.
- $\gamma$ is the gamma value of the RGB color system used. Many common ones may be found here.
- The output RGB values are in the nominal range [0.0, 1.0]. You may wish to scale them to some other range. For example,
if you want RGB in the range [0, 255], you must multiply each component by 255.0.
- If the input XYZ color is not relative to the same reference white as the RGB system, you must first apply a
chromatic adaptation transform to the XYZ color to convert
it from its own reference white to the reference white of the RGB system.
- Sometimes the more complicated special case of sRGB shown above is replaced by a "simplified" version using a straight gamma function with $\gamma = 2.2$.