1use std::ops;
4use std::u32;
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct Rgb {
7 pub r: u8,
9 pub g: u8,
11 pub b: u8,
13}
14
15impl Rgb {
16 #[inline]
18 pub const fn new(r: u8, g: u8, b: u8) -> Self {
19 Self { r, g, b }
20 }
21
22 #[inline]
24 pub const fn from_hex(hex: u32) -> Self {
25 Self::new((hex >> 16) as u8, (hex >> 8) as u8, hex as u8)
26 }
27
28 pub fn from_hex_string(hex: String) -> Self {
29 if hex.chars().count() == 8 && hex.starts_with("0x") {
30 let (_, value_string) = hex.split_at(2);
32 let int_val = u64::from_str_radix(value_string, 16);
34 match int_val {
35 Ok(num) => Self::new(
36 ((num & 0xff0000) >> 16) as u8,
37 ((num & 0xff00) >> 8) as u8,
38 (num & 0xff) as u8,
39 ),
40 _ => Self::new(0, 0, 0),
43 }
44 } else {
45 Self::new(0, 0, 0)
48 }
49 }
50
51 pub fn from_f32(r: f32, g: f32, b: f32) -> Self {
53 Self::new(
54 (r.clamp(0.0, 1.0) * 255.0) as u8,
55 (g.clamp(0.0, 1.0) * 255.0) as u8,
56 (b.clamp(0.0, 1.0) * 255.0) as u8,
57 )
58 }
59
60 #[inline]
62 pub const fn gray(x: u8) -> Self {
63 Self::new(x, x, x)
64 }
65
66 pub fn gray_f32(x: f32) -> Self {
68 Self::from_f32(x, x, x)
69 }
70
71 pub fn lerp(&self, other: Self, t: f32) -> Self {
101 let t = t.clamp(0.0, 1.0);
102 self * (1.0 - t) + other * t
103 }
104}
105
106impl From<(u8, u8, u8)> for Rgb {
107 fn from((r, g, b): (u8, u8, u8)) -> Self {
108 Self::new(r, g, b)
109 }
110}
111
112impl From<(f32, f32, f32)> for Rgb {
113 fn from((r, g, b): (f32, f32, f32)) -> Self {
114 Self::from_f32(r, g, b)
115 }
116}
117
118use crate::ANSIColorCode;
119use crate::TargetGround;
120impl ANSIColorCode for Rgb {
121 fn ansi_color_code(&self, target: TargetGround) -> String {
122 format!("{};2;{};{};{}", target.code() + 8, self.r, self.g, self.b)
123 }
124}
125
126overload::overload!(
127 (lhs: ?Rgb) + (rhs: ?Rgb) -> Rgb {
128 Rgb::new(
129 lhs.r.saturating_add(rhs.r),
130 lhs.g.saturating_add(rhs.g),
131 lhs.b.saturating_add(rhs.b)
132 )
133 }
134);
135
136overload::overload!(
137 (lhs: ?Rgb) - (rhs: ?Rgb) -> Rgb {
138 Rgb::new(
139 lhs.r.saturating_sub(rhs.r),
140 lhs.g.saturating_sub(rhs.g),
141 lhs.b.saturating_sub(rhs.b)
142 )
143 }
144);
145
146overload::overload!(
147 (lhs: ?Rgb) * (rhs: ?f32) -> Rgb {
148 Rgb::new(
149 (lhs.r as f32 * rhs.clamp(0.0, 1.0)) as u8,
150 (lhs.g as f32 * rhs.clamp(0.0, 1.0)) as u8,
151 (lhs.b as f32 * rhs.clamp(0.0, 1.0)) as u8
152 )
153 }
154);
155
156overload::overload!(
157 (lhs: ?f32) * (rhs: ?Rgb) -> Rgb {
158 Rgb::new(
159 (rhs.r as f32 * lhs.clamp(0.0, 1.0)) as u8,
160 (rhs.g as f32 * lhs.clamp(0.0, 1.0)) as u8,
161 (rhs.b as f32 * lhs.clamp(0.0, 1.0)) as u8
162 )
163 }
164);
165
166overload::overload!(
167 -(rgb: ?Rgb) -> Rgb {
168 Rgb::new(
169 255 - rgb.r,
170 255 - rgb.g,
171 255 - rgb.b)
172 }
173);