1use ansi_term::Colour::RGB;
2use image::Rgba;
3use std::cmp;
4use std::i64;
5
6const R: usize = 0;
7const G: usize = 1;
8const B: usize = 2;
9const A: usize = 3;
10
11pub trait Color {
12 fn r(&self) -> u8;
13 fn g(&self) -> u8;
14 fn b(&self) -> u8;
15 fn a(&self) -> u8;
16 fn rgb(&self) -> [u8; 3];
17 fn rgba(&self) -> [u8; 4];
18 fn hex(&self) -> String;
19 fn hexa(&self) -> String;
20 fn paint(&self, text: &str) -> String;
21 fn compare(&self, other: &Rgba<u8>) -> cmp::Ordering;
22}
23
24impl Color for Rgba<u8> {
25 fn r(&self) -> u8 {
26 return self[R];
27 }
28
29 fn g(&self) -> u8 {
30 return self[G];
31 }
32
33 fn b(&self) -> u8 {
34 return self[B];
35 }
36
37 fn a(&self) -> u8 {
38 return self[A];
39 }
40
41 fn rgb(&self) -> [u8; 3] {
42 return [self[R], self[G], self[B]];
43 }
44
45 fn rgba(&self) -> [u8; 4] {
46 return [self[R], self[G], self[B], self[A]];
47 }
48
49 fn hex(&self) -> String {
50 _to_hex(&self.rgb())
51 }
52
53 fn hexa(&self) -> String {
54 _to_hex(&self.rgba())
55 }
56
57 fn paint(&self, text: &str) -> String {
58 return RGB(self.r(), self.g(), self.b()).paint(text).to_string();
59 }
60
61 fn compare(&self, other: &Rgba<u8>) -> cmp::Ordering {
62 self.rgba()
63 .iter()
64 .zip(other.rgba().iter())
65 .map(|(a, b)| a.cmp(b))
66 .find(|&ord| ord != cmp::Ordering::Equal)
67 .unwrap_or(self.rgba().len().cmp(&other.rgba().len()))
68 }
69}
70
71pub fn from_hex(hex: String) -> Rgba<u8> {
72 Rgba(_from_hex(hex))
73}
74
75pub fn from_hexa(hex: String) -> Rgba<u8> {
76 Rgba(_from_hexa(hex))
77}
78
79fn _to_hex(hex: &[u8]) -> String {
80 hex.iter()
81 .map(|x| format!("{:02X}", x))
82 .fold(String::from(""), |acc, x| format!("{:}{:}", acc, x))
83}
84
85fn _from_hex(hex: String) -> [u8; 4] {
86 let trimmed_hex = hex.trim_start_matches("0x").trim_start_matches("#");
87 let num = i64::from_str_radix(&trimmed_hex, 16).unwrap();
88 let r_mask = 0xff0000;
89 let g_mask = 0x00ff00;
90 let b_mask = 0x0000ff;
91 let r = ((num & r_mask) >> 16) as u8;
92 let g = ((num & g_mask) >> 8) as u8;
93 let b = (num & b_mask) as u8;
94 [r, g, b, 255]
95}
96
97fn _from_hexa(hex: String) -> [u8; 4] {
98 let trimmed_hex = hex.trim_start_matches("0x").trim_start_matches("#");
99 let num = i64::from_str_radix(&trimmed_hex, 16).unwrap();
100 let r_mask = 0xff000000;
101 let g_mask = 0x00ff0000;
102 let b_mask = 0x0000ff00;
103 let a_mask = 0x000000ff;
104 let r = ((num & r_mask) >> 24) as u8;
105 let g = ((num & g_mask) >> 16) as u8;
106 let b = ((num & b_mask) >> 8) as u8;
107 let a = (num & a_mask) as u8;
108 [r, g, b, a]
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use crate::io;
115
116 #[test]
117 fn test_components() {
118 let img = io::open("src/test-image.png");
119 let pixel00 = img.get_pixel(0, 0);
121 assert_eq!(pixel00.r(), 255);
122 assert_eq!(pixel00.g(), 0);
123 assert_eq!(pixel00.b(), 0);
124 assert_eq!(pixel00.a(), 255);
125 let pixel30 = img.get_pixel(3, 0);
127 assert_eq!(pixel30.r(), 128);
128 assert_eq!(pixel30.g(), 255);
129 assert_eq!(pixel30.b(), 0);
130 assert_eq!(pixel30.a(), 255);
131 let pixel33 = img.get_pixel(3, 3);
133 assert_eq!(pixel33.r(), 0);
134 assert_eq!(pixel33.g(), 255);
135 assert_eq!(pixel33.b(), 255);
136 assert_eq!(pixel33.a(), 255);
137 let pixel03 = img.get_pixel(0, 3);
139 assert_eq!(pixel03.r(), 128);
140 assert_eq!(pixel03.g(), 0);
141 assert_eq!(pixel03.b(), 255);
142 assert_eq!(pixel03.a(), 255);
143 let pixel11 = img.get_pixel(1, 1);
145 assert_eq!(pixel11.r(), 255);
146 assert_eq!(pixel11.g(), 255);
147 assert_eq!(pixel11.b(), 255);
148 assert_eq!(pixel11.a(), 255);
149 let pixel21 = img.get_pixel(2, 1);
151 assert_eq!(pixel21.a(), 0);
152 let pixel12 = img.get_pixel(1, 2);
153 assert_eq!(pixel12.a(), 0);
154 let pixel31 = *img.get_pixel(3, 1);
156 assert_eq!(pixel31.rgb(), [0, 255, 0]);
157 assert_eq!(pixel31.rgba(), [0, 255, 0, 255]);
158 assert_eq!(pixel31.hex(), "00FF00");
159 assert_eq!(pixel31.hexa(), "00FF00FF");
160 }
161
162 #[test]
163 fn test_private_from_hex() {
164 assert_eq!(_from_hex(String::from("336699")), [51, 102, 153, 255]);
165 assert_eq!(_from_hex(String::from("0x336699")), [51, 102, 153, 255]);
166 assert_eq!(_from_hex(String::from("#336699")), [51, 102, 153, 255]);
167 }
168
169 #[test]
170 fn test_private_from_hexa() {
171 assert_eq!(_from_hexa(String::from("336699ff")), [51, 102, 153, 255]);
172 assert_eq!(_from_hexa(String::from("0x336699ff")), [51, 102, 153, 255]);
173 assert_eq!(_from_hexa(String::from("#336699ff")), [51, 102, 153, 255]);
174 }
175
176 #[test]
177 fn test_from_hex() {
178 let pixel = from_hex(String::from("336699"));
179 assert_eq!(pixel.rgb(), [51, 102, 153]);
180 let pixel = from_hex(String::from("0x336699"));
181 assert_eq!(pixel.rgb(), [51, 102, 153]);
182 let pixel = from_hex(String::from("#336699"));
183 assert_eq!(pixel.rgb(), [51, 102, 153]);
184 }
185
186 #[test]
187 fn test_from_hexa() {
188 let pixel = from_hexa(String::from("33669933"));
189 assert_eq!(pixel.rgba(), [51, 102, 153, 51]);
190 let pixel = from_hexa(String::from("0x33669966"));
191 assert_eq!(pixel.rgba(), [51, 102, 153, 102]);
192 let pixel = from_hexa(String::from("#33669966"));
193 assert_eq!(pixel.rgba(), [51, 102, 153, 102]);
194 }
195}