Skip to main content

supercode_frontend_tui/foundation/
color.rs

1// Derived from OpenAI Codex: codex-rs/tui/src/color.rs
2// Pinned source: 8604689ec5e3437eb79802d8d72249b7722fbf5b
3// Copyright 2025 OpenAI
4// Licensed under the Apache License, Version 2.0.
5// Modified by the Supercode contributors; see docs/legal/codex-frontend-extraction.toml.
6
7pub fn is_light(bg: (u8, u8, u8)) -> bool {
8    let (r, g, b) = bg;
9    let y = 0.299 * r as f32 + 0.587 * g as f32 + 0.114 * b as f32;
10    y > 128.0
11}
12
13pub fn blend(fg: (u8, u8, u8), bg: (u8, u8, u8), alpha: f32) -> (u8, u8, u8) {
14    let r = (fg.0 as f32 * alpha + bg.0 as f32 * (1.0 - alpha)) as u8;
15    let g = (fg.1 as f32 * alpha + bg.1 as f32 * (1.0 - alpha)) as u8;
16    let b = (fg.2 as f32 * alpha + bg.2 as f32 * (1.0 - alpha)) as u8;
17    (r, g, b)
18}
19
20/// Returns the perceptual color distance between two RGB colors.
21/// Uses the CIE76 formula (Euclidean distance in Lab space approximation).
22pub fn perceptual_distance(a: (u8, u8, u8), b: (u8, u8, u8)) -> f32 {
23    // Convert sRGB to linear RGB
24    fn srgb_to_linear(c: u8) -> f32 {
25        let c = c as f32 / 255.0;
26        if c <= 0.04045 {
27            c / 12.92
28        } else {
29            ((c + 0.055) / 1.055).powf(2.4)
30        }
31    }
32
33    // Convert RGB to XYZ
34    fn rgb_to_xyz(r: u8, g: u8, b: u8) -> (f32, f32, f32) {
35        let r = srgb_to_linear(r);
36        let g = srgb_to_linear(g);
37        let b = srgb_to_linear(b);
38
39        let x = r * 0.4124 + g * 0.3576 + b * 0.1805;
40        let y = r * 0.2126 + g * 0.7152 + b * 0.0722;
41        let z = r * 0.0193 + g * 0.1192 + b * 0.9505;
42        (x, y, z)
43    }
44
45    // Convert XYZ to Lab
46    fn xyz_to_lab(x: f32, y: f32, z: f32) -> (f32, f32, f32) {
47        // D65 reference white
48        let xr = x / 0.95047;
49        let yr = y / 1.00000;
50        let zr = z / 1.08883;
51
52        fn f(t: f32) -> f32 {
53            if t > 0.008856 {
54                t.powf(1.0 / 3.0)
55            } else {
56                7.787 * t + 16.0 / 116.0
57            }
58        }
59
60        let fx = f(xr);
61        let fy = f(yr);
62        let fz = f(zr);
63
64        let l = 116.0 * fy - 16.0;
65        let a = 500.0 * (fx - fy);
66        let b = 200.0 * (fy - fz);
67        (l, a, b)
68    }
69
70    let (x1, y1, z1) = rgb_to_xyz(a.0, a.1, a.2);
71    let (x2, y2, z2) = rgb_to_xyz(b.0, b.1, b.2);
72
73    let (l1, a1, b1) = xyz_to_lab(x1, y1, z1);
74    let (l2, a2, b2) = xyz_to_lab(x2, y2, z2);
75
76    let dl = l1 - l2;
77    let da = a1 - a2;
78    let db = b1 - b2;
79
80    (dl * dl + da * da + db * db).sqrt()
81}