Skip to content

Commit 0279591

Browse files
bors[bot]mswift42
andauthored
Merge #157
157: implement FromStr method for Srgb<f32>. r=Ogeon a=mswift42 This enables converting hex colors like '#00ddff' or '#fff' to Rgb. this closes #148. Co-authored-by: mswift42 <martin.haesler@gmail.com>
2 parents 0ac5dd2 + 4b4e0a4 commit 0279591

File tree

1 file changed

+126
-1
lines changed

1 file changed

+126
-1
lines changed

palette/src/rgb/rgb.rs

+126-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ use core::any::TypeId;
22
use core::fmt;
33
use core::marker::PhantomData;
44
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
5+
use core::str::FromStr;
6+
use core::num::ParseIntError;
57

68
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
79
use float::Float;
@@ -953,14 +955,92 @@ where
953955
}
954956
}
955957

958+
#[derive(Debug)]
959+
pub enum FromHexError {
960+
ParseIntError(ParseIntError),
961+
HexFormatError(&'static str)
962+
}
963+
964+
impl From<ParseIntError> for FromHexError {
965+
fn from(err: ParseIntError) -> FromHexError {
966+
FromHexError::ParseIntError(err)
967+
}
968+
}
969+
970+
impl From<&'static str> for FromHexError {
971+
fn from(err: &'static str) -> FromHexError {
972+
FromHexError::HexFormatError(err)
973+
}
974+
}
975+
impl core::fmt::Display for FromHexError {
976+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
977+
match &*self {
978+
FromHexError::ParseIntError(e) => {
979+
write!(f, "{}", e)
980+
}
981+
FromHexError::HexFormatError(s) => {
982+
write!(f, "{}, please use format '#fff', 'fff', '#ffffff' or\
983+
'ffffff'.", s)
984+
}
985+
}
986+
}
987+
}
988+
989+
#[cfg(feature="std")]
990+
impl std::error::Error for FromHexError {
991+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
992+
match &*self {
993+
FromHexError::HexFormatError(_s) => None,
994+
FromHexError::ParseIntError(e) => Some(e),
995+
}
996+
}
997+
}
998+
999+
1000+
impl<S: RgbStandard> FromStr for Rgb<S, u8> {
1001+
type Err = FromHexError;
1002+
1003+
// Parses a color hex code of format '#ff00bb' or '#abc' into a
1004+
// Rgb<S, u8> instance.
1005+
fn from_str(hex: &str) -> Result<Self, Self::Err> {
1006+
let hex_code = if hex.starts_with('#') {
1007+
&hex[1..]
1008+
} else {
1009+
hex
1010+
};
1011+
match hex_code.len() {
1012+
3 => {
1013+
let red = u8::from_str_radix(&hex_code[..1], 16)?;
1014+
let green = u8::from_str_radix(&hex_code[1..2], 16)?;
1015+
let blue = u8::from_str_radix(&hex_code[2..3], 16)?;
1016+
let col: Rgb<S, u8> = Rgb::new(
1017+
red * 17,
1018+
green * 17,
1019+
blue * 17,
1020+
);
1021+
Ok(col)
1022+
}
1023+
6 => {
1024+
let red = u8::from_str_radix(&hex_code[..2], 16)?;
1025+
let green = u8::from_str_radix(&hex_code[2..4], 16)?;
1026+
let blue = u8::from_str_radix(&hex_code[4..6], 16)?;
1027+
let col: Rgb<S, u8> = Rgb::new(red, green, blue);
1028+
Ok(col)
1029+
}
1030+
_ => Err("invalid hex code format".into()),
1031+
}
1032+
}
1033+
}
1034+
9561035
#[cfg(test)]
9571036
mod test {
9581037
use super::Rgb;
9591038
use encoding::Srgb;
1039+
use core::str::FromStr;
9601040

9611041
#[test]
9621042
fn ranges() {
963-
assert_ranges!{
1043+
assert_ranges! {
9641044
Rgb<Srgb, f64>;
9651045
limited {
9661046
red: 0.0 => 1.0,
@@ -1081,4 +1161,49 @@ mod test {
10811161

10821162
assert_eq!(deserialized, Rgb::<Srgb>::new(0.3, 0.8, 0.1));
10831163
}
1164+
1165+
#[test]
1166+
fn from_str() {
1167+
let c = Rgb::<Srgb, u8>::from_str("#ffffff");
1168+
assert!(c.is_ok());
1169+
assert_eq!(c.unwrap(), Rgb::<Srgb,u8>::new(255,255,255));
1170+
let c = Rgb::<Srgb, u8>::from_str("#gggggg");
1171+
assert!(c.is_err());
1172+
let c = Rgb::<Srgb,u8>::from_str("#fff");
1173+
assert!(c.is_ok());
1174+
assert_eq!(c.unwrap(),Rgb::<Srgb,u8>::new(255,255,255));
1175+
let c = Rgb::<Srgb,u8>::from_str("#000000");
1176+
assert!(c.is_ok());
1177+
assert_eq!(c.unwrap(), Rgb::<Srgb,u8>::new(0,0,0));
1178+
let c = Rgb::<Srgb,u8>::from_str("");
1179+
assert!(c.is_err());
1180+
let c = Rgb::<Srgb,u8>::from_str("#123456");
1181+
assert!(c.is_ok());
1182+
assert_eq!(c.unwrap(), Rgb::<Srgb,u8>::new(18, 52, 86));
1183+
let c = Rgb::<Srgb,u8>::from_str("#iii");
1184+
assert!(c.is_err());
1185+
assert_eq!(
1186+
format!("{}", c.err().unwrap()),
1187+
"invalid digit found in string"
1188+
);
1189+
let c = Rgb::<Srgb,u8>::from_str("#08f");
1190+
assert_eq!(c.unwrap(), Rgb::<Srgb,u8>::new(0, 136, 255));
1191+
let c = Rgb::<Srgb,u8>::from_str("08f");
1192+
assert_eq!(c.unwrap(), Rgb::<Srgb,u8>::new(0, 136,255));
1193+
let c = Rgb::<Srgb,u8>::from_str("ffffff");
1194+
assert_eq!(c.unwrap(), Rgb::<Srgb,u8>::new(255,255,255));
1195+
let c = Rgb::<Srgb,u8>::from_str("#12");
1196+
assert!(c.is_err());
1197+
assert_eq!(
1198+
format!("{}", c.err().unwrap()),
1199+
"invalid hex code format, \
1200+
please use format \'#fff\', \'fff\', \'#ffffff\' or\'ffffff\'."
1201+
);
1202+
let c = Rgb::<Srgb,u8>::from_str("da0bce");
1203+
assert_eq!(c.unwrap(), Rgb::<Srgb,u8>::new(218,11,206));
1204+
let c = Rgb::<Srgb,u8>::from_str("f034e6");
1205+
assert_eq!(c.unwrap(), Rgb::<Srgb,u8>::new(240,52,230));
1206+
let c = Rgb::<Srgb,u8>::from_str("abc");
1207+
assert_eq!(c.unwrap(), Rgb::<Srgb,u8>::new(170,187,204));
1208+
}
10841209
}

0 commit comments

Comments
 (0)