glifparser/
color.rs

1//! impl's/struct for shared `<image>`/`<guideline>`/layer color behavior
2
3use integer_or_float::IntegerOrFloat;
4
5use crate::error::GlifParserError;
6#[cfg(feature = "glifserde")]
7use serde::{Serialize, Deserialize};
8#[cfg_attr(feature = "glifserde", derive(Serialize, Deserialize))]
9#[derive(Debug, Default, Copy, Clone, PartialEq)]
10pub struct Color {
11    pub r: IntegerOrFloat,
12    pub g: IntegerOrFloat,
13    pub b: IntegerOrFloat,
14    pub a: IntegerOrFloat
15}
16
17impl Color {
18    pub fn from_rgba(r: IntegerOrFloat, g: IntegerOrFloat, b: IntegerOrFloat, a: IntegerOrFloat) -> Color {
19        Color { r, g, b, a }
20    }
21
22    pub fn as_plist_value(&self) -> plist::Value {
23        plist::Value::Array(vec![plist::Value::Real(self.r.into()), plist::Value::Real(self.g.into()), plist::Value::Real(self.b.into()), plist::Value::Real(self.a.into())])
24    }
25}
26
27use std::str::FromStr;
28use std::convert::TryFrom;
29
30/// This follows the UFO spec, e.g. `"0,0,1,1"` → blue at 100% opacity
31impl FromStr for Color {
32    type Err = GlifParserError;
33
34    fn from_str(s: &str) -> Result<Self, Self::Err> {
35        let mut to_parse = s.to_string();
36        to_parse.retain(|c| !c.is_whitespace());
37        let numbers: Vec<_> = s.split(',').collect();
38        if let Some(&[rr, gg, bb, aa]) = numbers.chunks(4).next() {
39            let convert_to_iof = |c: &str| -> Result<IntegerOrFloat, GlifParserError> {Ok(IntegerOrFloat::try_from(c).or(Err(GlifParserError::ColorNotRGBA))?)};
40            let r: IntegerOrFloat = convert_to_iof(rr)?;
41            let g: IntegerOrFloat = convert_to_iof(gg)?;
42            let b: IntegerOrFloat = convert_to_iof(bb)?;
43            let a: IntegerOrFloat = convert_to_iof(aa)?;
44            Ok(Color{r, g, b, a})
45        } else {
46            Err(GlifParserError::ColorNotRGBA)
47        }
48    }
49}
50
51/// This follows the UFO spec, not other specs that would say to do e.g. rgba(1,1,1,1)
52impl ToString for Color {
53    fn to_string(&self) -> String {
54        format!("{},{},{},{}", self.r.to_string(), self.g.to_string(), self.b.to_string(), self.a.to_string())
55    }
56}
57
58impl Into<[f32; 4]> for Color {
59    fn into(self) -> [f32; 4] {
60        [self.r.into(), self.g.into(), self.b.into(), self.a.into()]
61    }
62}
63
64impl From<[f32; 4]> for Color {
65    fn from(c: [f32; 4]) -> Self {
66        Color::from_rgba(c[0].into(), c[1].into(), c[2].into(), c[3].into())
67    }
68}