86 lines
2.4 KiB
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);
|
|
}
|