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}