ColorConversion.cpp [plain text]
#include "config.h"
#include "ColorConversion.h"
#include "ColorComponents.h"
#include "ColorMatrix.h"
#include "ColorTypes.h"
namespace WebCore {
float linearToRGBColorComponent(float c)
{
if (c < 0.0031308f)
return 12.92f * c;
return clampTo<float>(1.055f * std::pow(c, 1.0f / 2.4f) - 0.055f, 0, 1);
}
float rgbToLinearColorComponent(float c)
{
if (c <= 0.04045f)
return c / 12.92f;
return clampTo<float>(std::pow((c + 0.055f) / 1.055f, 2.4f), 0, 1);
}
LinearSRGBA<float> toLinearSRGBA(const SRGBA<float>& color)
{
return {
rgbToLinearColorComponent(color.red),
rgbToLinearColorComponent(color.green),
rgbToLinearColorComponent(color.blue),
color.alpha
};
}
SRGBA<float> toSRGBA(const LinearSRGBA<float>& color)
{
return {
linearToRGBColorComponent(color.red),
linearToRGBColorComponent(color.green),
linearToRGBColorComponent(color.blue),
color.alpha
};
}
LinearDisplayP3<float> toLinearDisplayP3(const DisplayP3<float>& color)
{
return {
rgbToLinearColorComponent(color.red),
rgbToLinearColorComponent(color.green),
rgbToLinearColorComponent(color.blue),
color.alpha
};
}
DisplayP3<float> toDisplayP3(const LinearDisplayP3<float>& color)
{
return {
linearToRGBColorComponent(color.red),
linearToRGBColorComponent(color.green),
linearToRGBColorComponent(color.blue),
color.alpha
};
}
static LinearSRGBA<float> toLinearSRGBA(const XYZA<float>& color)
{
constexpr ColorMatrix<3, 3> xyzToLinearSRGBMatrix {
3.2404542f, -1.5371385f, -0.4985314f,
-0.9692660f, 1.8760108f, 0.0415560f,
0.0556434f, -0.2040259f, 1.0572252f
};
return asLinearSRGBA(xyzToLinearSRGBMatrix.transformedColorComponents(asColorComponents(color)));
}
static XYZA<float> toXYZ(const LinearSRGBA<float>& color)
{
constexpr ColorMatrix<3, 3> linearSRGBToXYZMatrix {
0.4124564f, 0.3575761f, 0.1804375f,
0.2126729f, 0.7151522f, 0.0721750f,
0.0193339f, 0.1191920f, 0.9503041f
};
return asXYZA(linearSRGBToXYZMatrix.transformedColorComponents(asColorComponents(color)));
}
static LinearDisplayP3<float> toLinearDisplayP3(const XYZA<float>& color)
{
constexpr ColorMatrix<3, 3> xyzToLinearDisplayP3Matrix {
2.493496911941425f, -0.9313836179191239f, -0.4027107844507168f,
-0.8294889695615747f, 1.7626640603183463f, 0.0236246858419436f,
0.0358458302437845f, -0.0761723892680418f, 0.9568845240076872f
};
return asLinearDisplayP3(xyzToLinearDisplayP3Matrix.transformedColorComponents(asColorComponents(color)));
}
static XYZA<float> toXYZ(const LinearDisplayP3<float>& color)
{
constexpr ColorMatrix<3, 3> linearDisplayP3ToXYZMatrix {
0.4865709486482162f, 0.2656676931690931f, 0.198217285234363f,
0.2289745640697488f, 0.6917385218365064f, 0.079286914093745f,
0.0f, 0.0451133818589026f, 1.043944368900976f
};
return asXYZA(linearDisplayP3ToXYZMatrix.transformedColorComponents(asColorComponents(color)));
}
SRGBA<float> toSRGBA(const DisplayP3<float>& color)
{
return toSRGBA(toLinearSRGBA(toXYZ(toLinearDisplayP3(color))));
}
DisplayP3<float> toDisplayP3(const SRGBA<float>& color)
{
return toDisplayP3(toLinearDisplayP3(toXYZ(toLinearSRGBA(color))));
}
HSLA<float> toHSLA(const SRGBA<float>& color)
{
auto [r, g, b, alpha] = color;
auto [min, max] = std::minmax({ r, g, b });
float chroma = max - min;
float hue;
if (!chroma)
hue = 0;
else if (max == r)
hue = (60.0f * ((g - b) / chroma)) + 360.0f;
else if (max == g)
hue = (60.0f * ((b - r) / chroma)) + 120.0f;
else
hue = (60.0f * ((r - g) / chroma)) + 240.0f;
if (hue >= 360.0f)
hue -= 360.0f;
hue /= 360.0f;
float lightness = 0.5f * (max + min);
float saturation;
if (!chroma)
saturation = 0;
else if (lightness <= 0.5f)
saturation = (chroma / (max + min));
else
saturation = (chroma / (2.0f - (max + min)));
return {
hue,
saturation,
lightness,
alpha
};
}
static float calcHue(float temp1, float temp2, float hueVal)
{
if (hueVal < 0.0f)
hueVal += 6.0f;
else if (hueVal >= 6.0f)
hueVal -= 6.0f;
if (hueVal < 1.0f)
return temp1 + (temp2 - temp1) * hueVal;
if (hueVal < 3.0f)
return temp2;
if (hueVal < 4.0f)
return temp1 + (temp2 - temp1) * (4.0f - hueVal);
return temp1;
}
SRGBA<float> toSRGBA(const HSLA<float>& color)
{
auto [hue, saturation, lightness, alpha] = color;
if (!saturation) {
return {
lightness,
lightness,
lightness,
alpha
};
}
float temp2 = lightness <= 0.5f ? lightness * (1.0f + saturation) : lightness + saturation - lightness * saturation;
float temp1 = 2.0f * lightness - temp2;
hue *= 6.0f; return {
calcHue(temp1, temp2, hue + 2.0f),
calcHue(temp1, temp2, hue),
calcHue(temp1, temp2, hue - 2.0f),
alpha
};
}
SRGBA<float> toSRGBA(const CMYKA<float>& color)
{
auto [c, m, y, k, a] = color;
float colors = 1 - k;
float r = colors * (1.0f - c);
float g = colors * (1.0f - m);
float b = colors * (1.0f - y);
return { r, g, b, a };
}
}