color_art/color/
stringify.rs

1use crate::{
2    conversion::{
3        cmyk::rgb2cmyk,
4        hex::{rgb2hex, rgba2hex},
5        hsi::rgb2hsi,
6        hsl::rgb2hsl,
7        hsv::rgb2hsv,
8        hwb::rgb2hwb,
9        lab::rgb2lab,
10        xyz::rgb2xyz,
11        ycbcr::rgb2ycbcr,
12        yiq::rgb2yiq,
13        yuv::rgb2yuv,
14    },
15    data::name_of_hex,
16    utils::{hex::simplify_hex, round},
17    Color,
18};
19
20/// Stringify a color to a string.
21impl Color {
22    /// `hex` string of the color
23    ///
24    /// The hex string is simplified to a short hex string if possible.
25    ///
26    /// For example:
27    /// - `#ff00ff` -> `#f0f`
28    /// - `#ffffff88` -> `#fff8`
29    ///
30    /// # Examples
31    ///
32    /// ```rust
33    /// use color_art::Color;
34    ///
35    /// let color = Color::new(255, 0, 255, 1.0);
36    /// assert_eq!(color.hex(), "#f0f");
37    ///
38    /// let color = Color::new(255, 255, 255, 0.5);
39    /// assert_eq!(color.hex(), "#ffffff80");
40    /// ```
41    pub fn hex(self) -> String {
42        simplify_hex(self.hex_full())
43    }
44    /// `hex` string of the color with the full length.
45    ///
46    /// # Examples
47    ///
48    /// ```rust
49    /// use color_art::Color;
50    ///
51    /// let color = Color::new(255, 0, 255, 1.0);
52    /// assert_eq!(color.hex_full(), "#ff00ff");
53    /// ```
54    pub fn hex_full(self) -> String {
55        if self.alpha == 1.0 {
56            rgb2hex(self.rgb)
57        } else {
58            let [r, g, b] = self.rgb;
59            rgba2hex([r, g, b, self.alpha])
60        }
61    }
62    /// `rgb` string of the color
63    ///
64    /// # Examples
65    ///
66    /// ```rust
67    /// use color_art::Color;
68    ///
69    /// let color = Color::new(255.0, 255.0, 255.0, 1.0);
70    /// assert_eq!(color.rgb(), "rgb(255, 255, 255)");
71    /// ```
72    pub fn rgb(self) -> String {
73        let [r, g, b] = self.rgb;
74        let r = r.round() as u8;
75        let g = g.round() as u8;
76        let b = b.round() as u8;
77        format!("rgb({}, {}, {})", r, g, b)
78    }
79    /// `rgba` string of the color
80    ///
81    /// # Examples
82    ///
83    /// ```rust
84    /// use color_art::Color;
85    ///
86    /// let color = Color::new(255.0, 255.0, 255.0, 0.5);
87    /// assert_eq!(color.rgba(), "rgba(255, 255, 255, 0.5)");
88    /// ```
89    pub fn rgba(self) -> String {
90        let [r, g, b] = self.rgb;
91        let r = r.round() as u8;
92        let g = g.round() as u8;
93        let b = b.round() as u8;
94        format!("rgba({}, {}, {}, {})", r, g, b, self.alpha())
95    }
96    /// `hsl` string of the color
97    ///
98    /// # Examples
99    ///
100    /// ```rust
101    /// use color_art::Color;
102    ///
103    /// let color = Color::new(255.0, 255.0, 255.0, 1.0);
104    /// assert_eq!(color.hsl(), "hsl(0, 0%, 100%)");
105    /// ```
106    pub fn hsl(self) -> String {
107        let hsl = rgb2hsl(&self.rgb);
108        let h = round(hsl[0], 0);
109        let s = round(hsl[1] * 100.0, 0);
110        let l = round(hsl[2] * 100.0, 0);
111        format!("hsl({}, {}%, {}%)", h, s, l)
112    }
113    /// `hsla` string of the color
114    ///
115    /// # Examples
116    ///
117    /// ```rust
118    /// use color_art::Color;
119    ///
120    /// let color = Color::new(255, 255, 255, 0.3);
121    /// assert_eq!(color.hsla(), "hsla(0, 0%, 100%, 0.3)");
122    /// ```
123    pub fn hsla(self) -> String {
124        let hsl = rgb2hsl(&self.rgb);
125        let h = round(hsl[0], 0);
126        let s = round(hsl[1] * 100.0, 0);
127        let l = round(hsl[2] * 100.0, 0);
128        format!("hsla({}, {}%, {}%, {})", h, s, l, self.alpha())
129    }
130    /// `hsv` string of the color
131    ///
132    /// # Examples
133    ///
134    /// ```rust
135    /// use color_art::Color;
136    ///
137    /// let color = Color::new(255.0, 255.0, 255.0, 1.0);
138    /// assert_eq!(color.hsv(), "hsv(0, 0%, 100%)");
139    /// ```
140    pub fn hsv(self) -> String {
141        let hsv = rgb2hsv(&self.rgb);
142        let h = round(hsv[0], 0);
143        let s = round(hsv[1] * 100.0, 0);
144        let v = round(hsv[2] * 100.0, 0);
145        format!("hsv({}, {}%, {}%)", h, s, v)
146    }
147    /// `hsi` string of the color
148    ///
149    /// # Examples
150    ///
151    /// ```rust
152    /// use color_art::Color;
153    ///
154    /// let color = Color::new(255, 255, 255, 1.0);
155    /// assert_eq!(color.hsi(), "hsi(0, 0%, 100%)");
156    /// ```
157    pub fn hsi(self) -> String {
158        let hsi = rgb2hsi(&self.rgb);
159        let h = round(hsi[0], 0);
160        let s = round(hsi[1] * 100.0, 2);
161        let i = round(hsi[2] * 100.0, 2);
162        format!("hsi({}, {}%, {}%)", h, s, i)
163    }
164    /// `hwb` string of the color
165    ///
166    /// # Examples
167    ///
168    /// ```rust
169    /// use color_art::Color;
170    ///
171    /// let color = Color::new(255.0, 255.0, 255.0, 1.0);
172    /// assert_eq!(color.hwb(), "hwb(0, 100%, 0%)");
173    /// ```
174    pub fn hwb(self) -> String {
175        let hwb = rgb2hwb(&self.rgb);
176        let h = round(hwb[0], 0);
177        let w = round(hwb[1] * 100.0, 0);
178        let b = round(hwb[2] * 100.0, 0);
179        format!("hwb({}, {}%, {}%)", h, w, b)
180    }
181    /// `cmyk` string of the color
182    ///
183    /// # Examples
184    ///
185    /// ```rust
186    /// use color_art::Color;
187    ///
188    /// let color = Color::new(255.0, 255.0, 255.0, 1.0);
189    /// assert_eq!(color.cmyk(), "cmyk(0%, 0%, 0%, 0%)");
190    /// ```
191    pub fn cmyk(self) -> String {
192        let cmyk = rgb2cmyk(&self.rgb)
193            .iter()
194            .map(|&v| round(v * 100.0, 0))
195            .collect::<Vec<_>>();
196        format!(
197            "cmyk({}%, {}%, {}%, {}%)",
198            cmyk[0], cmyk[1], cmyk[2], cmyk[3]
199        )
200    }
201    /// `xyz` string of the color
202    ///
203    /// # Examples
204    ///
205    /// ```rust
206    /// use color_art::Color;
207    ///
208    /// let color = Color::new(255.0, 0.0, 0.0, 1.0);
209    /// assert_eq!(color.xyz(), "xyz(0.412391, 0.212639, 0.019331)");
210    /// ```
211    pub fn xyz(self) -> String {
212        let xyz = rgb2xyz(&self.rgb)
213            .iter()
214            .map(|&v| round(v, 6))
215            .collect::<Vec<_>>();
216        format!("xyz({}, {}, {})", xyz[0], xyz[1], xyz[2])
217    }
218    /// `yiq` string of the color
219    ///
220    /// # Examples
221    ///
222    /// ```rust
223    /// use color_art::Color;
224    ///
225    /// let color = Color::new(255.0, 0.0, 0.0, 1.0);
226    /// assert_eq!(color.yiq(), "yiq(0.299, 0.59572, 0.21146)");
227    /// ```
228    pub fn yiq(self) -> String {
229        let yiq = rgb2yiq(&self.rgb)
230            .iter()
231            .map(|&v| round(v, 5))
232            .collect::<Vec<_>>();
233        format!("yiq({}, {}, {})", yiq[0], yiq[1], yiq[2])
234    }
235    /// `yuv` string of the color
236    ///
237    /// # Examples
238    ///
239    /// ```rust
240    /// use color_art::Color;
241    ///
242    /// let color = Color::new(255.0, 0.0, 0.0, 1.0);
243    /// assert_eq!(color.yuv(), "yuv(0.299, -0.1471, 0.6148)");
244    /// ```
245    pub fn yuv(self) -> String {
246        let yuv = rgb2yuv(&self.rgb)
247            .iter()
248            .map(|&v| round(v, 4))
249            .collect::<Vec<_>>();
250        format!("yuv({}, {}, {})", yuv[0], yuv[1], yuv[2])
251    }
252    /// `lab` string of the color
253    ///
254    /// # Examples
255    ///
256    /// ```rust
257    /// use color_art::Color;
258    ///
259    /// let color = Color::new(255.0, 255.0, 0.0, 1.0);
260    /// assert_eq!(color.lab(), "lab(97.61, -15.75, 93.39)");
261    /// ```
262    pub fn lab(self) -> String {
263        let lab = rgb2lab(&self.rgb)
264            .iter()
265            .map(|&v| round(v, 2))
266            .collect::<Vec<_>>();
267        format!("lab({}, {}, {})", lab[0], lab[1], lab[2])
268    }
269    /// `YCbCr` string of the color
270    ///
271    /// # Examples
272    ///
273    /// ```rust
274    /// use color_art::Color;
275    ///
276    /// let color = Color::new(255.0, 255.0, 0.0, 1.0);
277    /// assert_eq!(color.ycbcr(), "YCbCr(225.93, 0.5755, 148.7269)");
278    /// ```
279    pub fn ycbcr(self) -> String {
280        let ycbcr = rgb2ycbcr(&self.rgb)
281            .iter()
282            .map(|&v| round(v, 4))
283            .collect::<Vec<_>>();
284        format!("YCbCr({}, {}, {})", ycbcr[0], ycbcr[1], ycbcr[2])
285    }
286    /// `name` of the color
287    ///
288    /// The color name is based on the [CSS3 color name](https://www.w3.org/TR/css-color-3/#svg-color) or 中国传统色彩.
289    ///
290    /// If the color is not named, the hex string will be returned.
291    ///
292    /// # Examples
293    ///
294    /// ```rust
295    /// use color_art::{Color, color};
296    ///
297    /// let color = color!(#ffffff);
298    /// assert_eq!(color.name(), "white");
299    ///
300    /// let color = color!(#f8df72);
301    /// assert_eq!(color.name(), "茉莉黄");
302    ///
303    /// let color = Color::new(42, 42, 42, 1.0);
304    /// assert_eq!(color.name(), "#2a2a2a");
305    /// ```
306    pub fn name(self) -> String {
307        if self.alpha == 1.0 {
308            let hex = rgb2hex(self.rgb);
309            match name_of_hex(&hex) {
310                Some(name) => name.to_string(),
311                None => hex,
312            }
313        } else {
314            self.hex()
315        }
316    }
317}
318
319#[cfg(test)]
320mod tests {
321    use super::*;
322
323    #[test]
324    fn test_stringify_color() {
325        let color = Color::new(255.0, 255.0, 255.0, 1.0);
326        assert_eq!(color.hex(), "#fff");
327        assert_eq!(color.hex_full(), "#ffffff");
328        assert_eq!(color.rgb(), "rgb(255, 255, 255)");
329        assert_eq!(color.rgba(), "rgba(255, 255, 255, 1)");
330        assert_eq!(color.hsl(), "hsl(0, 0%, 100%)");
331        assert_eq!(color.hsla(), "hsla(0, 0%, 100%, 1)");
332        assert_eq!(color.hsv(), "hsv(0, 0%, 100%)");
333        assert_eq!(color.hsi(), "hsi(0, 0%, 100%)");
334        assert_eq!(color.hwb(), "hwb(0, 100%, 0%)");
335        assert_eq!(color.xyz(), "xyz(0.950456, 1, 1.089058)");
336        assert_eq!(color.ycbcr(), "YCbCr(255, 128, 128)");
337        assert_eq!(color.lab(), "lab(100, 0, 0)");
338        assert_eq!(color.name(), "white");
339
340        let color = Color::new(0.0, 0.0, 0.0, 0.2);
341        assert_eq!(color.hex(), "#0003");
342        assert_eq!(color.hex_full(), "#00000033");
343        assert_eq!(color.rgb(), "rgb(0, 0, 0)");
344        assert_eq!(color.rgba(), "rgba(0, 0, 0, 0.2)");
345        assert_eq!(color.hsl(), "hsl(0, 0%, 0%)");
346        assert_eq!(color.hsla(), "hsla(0, 0%, 0%, 0.2)");
347        assert_eq!(color.hsv(), "hsv(0, 0%, 0%)");
348        assert_eq!(color.hsi(), "hsi(0, 0%, 0%)");
349        assert_eq!(color.hwb(), "hwb(0, 0%, 100%)");
350        assert_eq!(color.xyz(), "xyz(0, 0, 0)");
351        assert_eq!(color.ycbcr(), "YCbCr(0, 128, 128)");
352        assert_eq!(color.lab(), "lab(0, 0, 0)");
353        assert_eq!(color.name(), "#0003");
354
355        let color = Color::new(0.0, 128.0, 128.0, 1.0);
356        assert_eq!(color.hex(), "#008080");
357        assert_eq!(color.hex_full(), "#008080");
358        assert_eq!(color.rgb(), "rgb(0, 128, 128)");
359        assert_eq!(color.rgba(), "rgba(0, 128, 128, 1)");
360        assert_eq!(color.hsl(), "hsl(180, 100%, 25%)");
361        assert_eq!(color.hsla(), "hsla(180, 100%, 25%, 1)");
362        assert_eq!(color.hsv(), "hsv(180, 100%, 50%)");
363        assert_eq!(color.hsi(), "hsi(180, 100%, 33.46%)");
364        assert_eq!(color.hwb(), "hwb(180, 0%, 50%)");
365        assert_eq!(color.xyz(), "xyz(0.116147, 0.16996, 0.230912)");
366        assert_eq!(color.ycbcr(), "YCbCr(89.728, 149.5854, 64.0239)");
367        assert_eq!(color.lab(), "lab(47.99, -30.39, -8.98)");
368        assert_eq!(color.name(), "teal");
369
370        let color = Color::new(161, 110, 87, 1.0);
371        assert_eq!(color.hex(), "#a16e57");
372        assert_eq!(color.hex_full(), "#a16e57");
373        assert_eq!(color.rgb(), "rgb(161, 110, 87)");
374        assert_eq!(color.rgba(), "rgba(161, 110, 87, 1)");
375        assert_eq!(color.hsl(), "hsl(19, 30%, 49%)");
376        assert_eq!(color.hsla(), "hsla(19, 30%, 49%, 1)");
377        assert_eq!(color.hsv(), "hsv(19, 46%, 63%)");
378        assert_eq!(color.hsi(), "hsi(18, 27.09%, 46.8%)");
379        assert_eq!(color.hwb(), "hwb(19, 34%, 37%)");
380        assert_eq!(color.xyz(), "xyz(0.219934, 0.194179, 0.116068)");
381        assert_eq!(color.ycbcr(), "YCbCr(122.627, 107.9064, 155.3599)");
382        assert_eq!(color.lab(), "lab(51.48, 18.82, 21.44)");
383        assert_eq!(color.name(), "#a16e57");
384    }
385}