mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 10:07:44 +00:00
LibGfx: Add Oklab support to Gfx::Color
Interpolation of color on the web is done via the oklab colorspace
This commit is contained in:
parent
71a784741f
commit
70ded2ef42
2 changed files with 64 additions and 6 deletions
|
@ -32,6 +32,12 @@ struct YUV {
|
||||||
float v { 0 };
|
float v { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Oklab {
|
||||||
|
float L { 0 };
|
||||||
|
float a { 0 };
|
||||||
|
float b { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
class Color {
|
class Color {
|
||||||
public:
|
public:
|
||||||
enum NamedColor {
|
enum NamedColor {
|
||||||
|
@ -159,6 +165,58 @@ public:
|
||||||
return Color(r_u8, g_u8, b_u8, a_u8);
|
return Color(r_u8, g_u8, b_u8, a_u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://bottosson.github.io/posts/oklab/
|
||||||
|
static constexpr Color from_oklab(float L, float a, float b, float alpha = 1.0f)
|
||||||
|
{
|
||||||
|
auto linear_to_srgb = [](float c) {
|
||||||
|
return c >= 0.0031308f ? 1.055f * pow(c, 0.4166666f) - 0.055f : 12.92f * c;
|
||||||
|
};
|
||||||
|
|
||||||
|
float l = L + 0.3963377774f * a + 0.2158037573f * b;
|
||||||
|
float m = L - 0.1055613458f * a - 0.0638541728f * b;
|
||||||
|
float s = L - 0.0894841775f * a - 1.2914855480f * b;
|
||||||
|
|
||||||
|
l = l * l * l;
|
||||||
|
m = m * m * m;
|
||||||
|
s = s * s * s;
|
||||||
|
|
||||||
|
float red = 4.0767416621f * l - 3.3077115913f * m + 0.2309699292f * s;
|
||||||
|
float green = -1.2684380046f * l + 2.6097574011f * m - 0.3413193965f * s;
|
||||||
|
float blue = -0.0041960863f * l - 0.7034186147f * m + 1.7076147010f * s;
|
||||||
|
|
||||||
|
red = linear_to_srgb(red) * 255.f;
|
||||||
|
green = linear_to_srgb(green) * 255.f;
|
||||||
|
blue = linear_to_srgb(blue) * 255.f;
|
||||||
|
|
||||||
|
return Color(
|
||||||
|
clamp(lroundf(red), 0, 255),
|
||||||
|
clamp(lroundf(green), 0, 255),
|
||||||
|
clamp(lroundf(blue), 0, 255),
|
||||||
|
clamp(lroundf(alpha * 255.f), 0, 255));
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://bottosson.github.io/posts/oklab/
|
||||||
|
constexpr Oklab to_oklab()
|
||||||
|
{
|
||||||
|
auto srgb_to_linear = [](float c) {
|
||||||
|
return c >= 0.04045f ? pow((c + 0.055f) / 1.055f, 2.4f) : c / 12.92f;
|
||||||
|
};
|
||||||
|
|
||||||
|
float r = srgb_to_linear(red() / 255.f);
|
||||||
|
float g = srgb_to_linear(green() / 255.f);
|
||||||
|
float b = srgb_to_linear(blue() / 255.f);
|
||||||
|
|
||||||
|
float l = cbrtf(0.4122214708f * r + 0.5363325363f * g + 0.0514459929f * b);
|
||||||
|
float m = cbrtf(0.2119034982f * r + 0.6806995451f * g + 0.1073969566f * b);
|
||||||
|
float s = cbrtf(0.0883024619f * r + 0.2817188376f * g + 0.6299787005f * b);
|
||||||
|
|
||||||
|
return {
|
||||||
|
0.2104542553f * l + 0.7936177850f * m - 0.0040720468f * s,
|
||||||
|
1.9779984951f * l - 2.4285922050f * m + 0.4505937099f * s,
|
||||||
|
0.0259040371f * l + 0.7827717662f * m - 0.8086757660f * s,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
constexpr u8 red() const { return (m_value >> 16) & 0xff; }
|
constexpr u8 red() const { return (m_value >> 16) & 0xff; }
|
||||||
constexpr u8 green() const { return (m_value >> 8) & 0xff; }
|
constexpr u8 green() const { return (m_value >> 8) & 0xff; }
|
||||||
constexpr u8 blue() const { return m_value & 0xff; }
|
constexpr u8 blue() const { return m_value & 0xff; }
|
||||||
|
|
|
@ -771,13 +771,13 @@ static ErrorOr<NonnullRefPtr<StyleValue>> interpolate_property(StyleValue const&
|
||||||
case StyleValue::Type::Color: {
|
case StyleValue::Type::Color: {
|
||||||
auto from_color = from.as_color().color();
|
auto from_color = from.as_color().color();
|
||||||
auto to_color = to.as_color().color();
|
auto to_color = to.as_color().color();
|
||||||
auto from_hsv = from_color.to_hsv();
|
auto from_oklab = from_color.to_oklab();
|
||||||
auto to_hsv = to_color.to_hsv();
|
auto to_oklab = to_color.to_oklab();
|
||||||
|
|
||||||
auto color = Color::from_hsv(
|
auto color = Color::from_oklab(
|
||||||
interpolate_raw(from_hsv.hue, to_hsv.hue),
|
interpolate_raw(from_oklab.L, to_oklab.L),
|
||||||
interpolate_raw(from_hsv.saturation, to_hsv.saturation),
|
interpolate_raw(from_oklab.a, to_oklab.a),
|
||||||
interpolate_raw(from_hsv.value, to_hsv.value));
|
interpolate_raw(from_oklab.b, to_oklab.b));
|
||||||
color.set_alpha(interpolate_raw(from_color.alpha(), to_color.alpha()));
|
color.set_alpha(interpolate_raw(from_color.alpha(), to_color.alpha()));
|
||||||
|
|
||||||
return ColorStyleValue::create(color);
|
return ColorStyleValue::create(color);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue