Initial implementation of invert() (no support for weight argument)

This commit is contained in:
ConnorSkees 2020-02-09 13:31:58 -05:00
parent 8638e2f251
commit 1269c9f662
6 changed files with 65 additions and 30 deletions

View File

@ -150,4 +150,10 @@ pub(crate) fn register(f: &mut BTreeMap<String, Builtin>) {
_ => todo!("non-color given to builtin function `alpha()`")
}
});
decl!(f "invert", |args, _| {
match arg!(args, 0, "color") {
Value::Color(c) => Some(Value::Color(c.invert())),
_ => todo!("non-color given to builtin function `alpha()`")
}
});
}

View File

@ -10,15 +10,15 @@ mod name;
#[derive(Debug, Clone, Eq, PartialEq)]
pub(crate) struct Color {
red: u16,
green: u16,
blue: u16,
red: u8,
green: u8,
blue: u8,
alpha: Number,
repr: String,
}
impl Color {
pub fn new(red: u16, green: u16, blue: u16, alpha: u16, repr: String) -> Self {
pub fn new(red: u8, green: u8, blue: u8, alpha: u8, repr: String) -> Self {
Color {
red,
green,
@ -28,15 +28,15 @@ impl Color {
}
}
pub const fn red(&self) -> u16 {
pub const fn red(&self) -> u8 {
self.red
}
pub const fn blue(&self) -> u16 {
pub const fn blue(&self) -> u8 {
self.blue
}
pub const fn green(&self) -> u16 {
pub const fn green(&self) -> u8 {
self.green
}
@ -122,7 +122,7 @@ impl Color {
};
let val = (luminance.clone() * Number::from(255))
.to_integer()
.to_u16()
.to_u8()
.unwrap();
let repr = repr(val, val, val, &alpha);
return Color {
@ -175,8 +175,8 @@ impl Color {
} * Number::from(255))
.round()
.to_integer()
.to_u16()
.expect("expected channel to fit inside u16");
.to_u8()
.expect("expected channel to fit inside u8");
};
}
@ -198,11 +198,11 @@ impl Color {
macro_rules! clamp {
($channel:ident) => {
let $channel = if $channel > Number::from(255) {
255_u16
255_u8
} else if $channel < Number::from(0) {
0_u16
0_u8
} else {
$channel.round().to_integer().to_u16().unwrap()
$channel.round().to_integer().to_u8().unwrap()
};
};
}
@ -211,6 +211,14 @@ impl Color {
clamp!(green);
clamp!(blue);
let alpha = if alpha > Number::from(1) {
Number::from(1)
} else if alpha < Number::from(0) {
Number::from(0)
} else {
alpha
};
let repr = repr(red, green, blue, &alpha);
Color {
red,
@ -220,10 +228,24 @@ impl Color {
repr,
}
}
pub fn invert(&self) -> Self {
let red = std::u8::MAX - self.red;
let green = std::u8::MAX - self.green;
let blue = std::u8::MAX - self.blue;
let repr = repr(red, green, blue, &self.alpha);
Color {
red,
green,
blue,
alpha: self.alpha.clone(),
repr,
}
}
}
/// Get the proper representation from RGBA values
fn repr(red: u16, green: u16, blue: u16, alpha: &Number) -> String {
fn repr(red: u8, green: u8, blue: u8, alpha: &Number) -> String {
if alpha < &Number::from(1) {
format!("rgba({}, {}, {}, {})", red, green, blue, alpha)
} else if let Ok(c) = ColorName::try_from([red, green, blue]) {

View File

@ -469,10 +469,11 @@ impl TryFrom<&str> for ColorName {
}
}
}
impl TryFrom<[u16; 3]> for ColorName {
impl TryFrom<[u8; 3]> for ColorName {
type Error = &'static str;
fn try_from(c: [u16; 3]) -> Result<Self, Self::Error> {
fn try_from(c: [u8; 3]) -> Result<Self, Self::Error> {
match c {
[0xF0, 0xF8, 0xFF] => Ok(Self::AliceBlue),
[0xFA, 0xEB, 0xD7] => Ok(Self::AntiqueWhite),

View File

@ -61,6 +61,7 @@ macro_rules! from_integer {
from_integer!(u16);
from_integer!(usize);
from_integer!(i32);
from_integer!(u8);
impl Display for Number {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

View File

@ -20,32 +20,32 @@ fn parse_hex(s: String) -> Value {
match s.len() {
3 => {
let v = u16::from_str_radix(&s, 16).unwrap();
let red = ((v & 0xf00) >> 8) * 0x11;
let green = ((v & 0x0f0) >> 4) * 0x11;
let blue = (v & 0x00f) * 0x11;
let red = (((v & 0xf00) >> 8) * 0x11) as u8;
let green = (((v & 0x0f0) >> 4) * 0x11) as u8;
let blue = ((v & 0x00f) * 0x11) as u8;
Value::Color(Color::new(red, green, blue, 1, format!("#{}", s)))
}
4 => {
let v = u16::from_str_radix(&s, 16).unwrap();
let red = ((v & 0xf000) >> 12) * 0x11;
let green = ((v & 0x0f00) >> 8) * 0x11;
let blue = ((v & 0x00f0) >> 4) * 0x11;
let alpha = (v & 0x000f) * 0x11;
let red = (((v & 0xf000) >> 12) * 0x11) as u8;
let green = (((v & 0x0f00) >> 8) * 0x11) as u8;
let blue = (((v & 0x00f0) >> 4) * 0x11) as u8;
let alpha = ((v & 0x000f) * 0x11) as u8;
Value::Color(Color::new(red, green, blue, alpha, format!("#{}", s)))
}
6 => {
let v = u32::from_str_radix(&s, 16).unwrap();
let red: u16 = ((v & 0x00ff_0000) >> 16) as u16;
let green: u16 = ((v & 0x0000_ff00) >> 8) as u16;
let blue: u16 = (v & 0x0000_00ff) as u16;
let red = ((v & 0x00ff_0000) >> 16) as u8;
let green = ((v & 0x0000_ff00) >> 8) as u8;
let blue = (v & 0x0000_00ff) as u8;
Value::Color(Color::new(red, green, blue, 1, format!("#{}", s)))
}
8 => {
let v = u32::from_str_radix(&s, 16).unwrap();
let red = ((v & 0xff00_0000) >> 24) as u16;
let green = ((v & 0x00ff_0000) >> 16) as u16;
let blue = ((v & 0x0000_ff00) >> 8) as u16;
let alpha = (v & 0x0000_00ff) as u16;
let red = ((v & 0xff00_0000) >> 24) as u8;
let green = ((v & 0x00ff_0000) >> 16) as u8;
let blue = ((v & 0x0000_ff00) >> 8) as u8;
let alpha = (v & 0x0000_00ff) as u8;
Value::Color(Color::new(red, green, blue, alpha, format!("#{}", s)))
}
_ => Value::Ident(s, QuoteKind::None),

View File

@ -171,3 +171,8 @@ test!(
"$a: hsl(193, 67%, 28%);\n\na {\n color: lightness($a);\n}\n",
"a {\n color: 28%;\n}\n"
);
test!(
invert_no_weight,
"a {\n color: invert(white);\n}\n",
"a {\n color: black;\n}\n"
);