flow/src/color.zig

86 lines
2.4 KiB
Zig

const pow = @import("std").math.pow;
pub const RGB = struct {
r: u8,
g: u8,
b: u8,
pub inline fn from_u24(v: u24) RGB {
const r = @as(u8, @intCast(v >> 16 & 0xFF));
const g = @as(u8, @intCast(v >> 8 & 0xFF));
const b = @as(u8, @intCast(v & 0xFF));
return .{ .r = r, .g = g, .b = b };
}
pub inline fn to_u24(v: RGB) u24 {
const r = @as(u24, @intCast(v.r)) << 16;
const g = @as(u24, @intCast(v.g)) << 8;
const b = @as(u24, @intCast(v.b));
return r | b | g;
}
pub inline fn from_u8s(v: [3]u8) RGB {
return .{ .r = v[0], .g = v[1], .b = v[2] };
}
pub fn to_u8s(v: RGB) [3]u8 {
return [_]u8{ v.r, v.g, v.b };
}
pub fn contrast(a_: RGB, b_: RGB) f32 {
const a = RGBf.from_RGB(a_).luminance();
const b = RGBf.from_RGB(b_).luminance();
return (@max(a, b) + 0.05) / (@min(a, b) + 0.05);
}
pub fn max_contrast(v: RGB, a: RGB, b: RGB) RGB {
return if (contrast(v, a) > contrast(v, b)) a else b;
}
};
pub const RGBf = struct {
r: f32,
g: f32,
b: f32,
pub inline fn from_RGB(v: RGB) RGBf {
return .{ .r = tof(v.r), .g = tof(v.g), .b = tof(v.b) };
}
pub fn luminance(v: RGBf) f32 {
return linear(v.r) * RED + linear(v.g) * GREEN + linear(v.b) * BLUE;
}
inline fn tof(c: u8) f32 {
return @as(f32, @floatFromInt(c)) / 255.0;
}
inline fn linear(v: f32) f32 {
return if (v <= 0.03928) v / 12.92 else pow(f32, (v + 0.055) / 1.055, GAMMA);
}
const RED = 0.2126;
const GREEN = 0.7152;
const BLUE = 0.0722;
const GAMMA = 2.4;
};
pub fn max_contrast(v: u24, a: u24, b: u24) u24 {
return RGB.max_contrast(RGB.from_u24(v), RGB.from_u24(a), RGB.from_u24(b)).to_u24();
}
pub fn apply_alpha(base: RGB, over: RGB, alpha_u8: u8) RGB {
const alpha: f64 = @as(f64, @floatFromInt(alpha_u8)) / @as(f64, @floatFromInt(0xFF));
return .{
.r = component_apply_alpha(base.r, over.r, alpha),
.g = component_apply_alpha(base.g, over.g, alpha),
.b = component_apply_alpha(base.b, over.b, alpha),
};
}
inline fn component_apply_alpha(base_u8: u8, over_u8: u8, alpha: f64) u8 {
const base: f64 = @floatFromInt(base_u8);
const over: f64 = @floatFromInt(over_u8);
const result = ((1 - alpha) * base) + (alpha * over);
return @intFromFloat(result);
}