imgdata/
color.rs

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        // Red
120        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        // Yellow-green
126        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        // Cyan
132        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        // Purple
138        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        // White
144        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        // Transparent
150        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        // Green
155        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}