Round to nearest u8 instead of flooring

This commit is contained in:
Laurenz 2022-09-25 21:44:57 +02:00
parent 680cc9aa93
commit 2661f1a506
2 changed files with 44 additions and 45 deletions

View File

@ -70,23 +70,19 @@ impl Color {
/// Lighten this color by the given factor. /// Lighten this color by the given factor.
pub fn lighten(self, factor: Ratio) -> Self { pub fn lighten(self, factor: Ratio) -> Self {
let ratio = factor.get();
match self { match self {
Self::Luma(luma) => Self::Luma(luma.lighten(ratio)), Self::Luma(luma) => Self::Luma(luma.lighten(factor)),
Self::Rgba(rgba) => Self::Rgba(rgba.lighten(ratio)), Self::Rgba(rgba) => Self::Rgba(rgba.lighten(factor)),
Self::Cmyk(cmyk) => Self::Cmyk(cmyk.lighten(ratio)), Self::Cmyk(cmyk) => Self::Cmyk(cmyk.lighten(factor)),
} }
} }
/// Darken this color by the given factor. /// Darken this color by the given factor.
pub fn darken(self, factor: Ratio) -> Self { pub fn darken(self, factor: Ratio) -> Self {
let ratio = factor.get();
match self { match self {
Self::Luma(luma) => Self::Luma(luma.darken(ratio)), Self::Luma(luma) => Self::Luma(luma.darken(factor)),
Self::Rgba(rgba) => Self::Rgba(rgba.darken(ratio)), Self::Rgba(rgba) => Self::Rgba(rgba.darken(factor)),
Self::Cmyk(cmyk) => Self::Cmyk(cmyk.darken(ratio)), Self::Cmyk(cmyk) => Self::Cmyk(cmyk.darken(factor)),
} }
} }
@ -128,21 +124,23 @@ impl LumaColor {
/// Convert to CMYK as a fraction of true black. /// Convert to CMYK as a fraction of true black.
pub fn to_cmyk(self) -> CmykColor { pub fn to_cmyk(self) -> CmykColor {
CmykColor::new( CmykColor::new(
(self.0 as f64 * 0.75) as u8, round_u8(self.0 as f64 * 0.75),
(self.0 as f64 * 0.68) as u8, round_u8(self.0 as f64 * 0.68),
(self.0 as f64 * 0.67) as u8, round_u8(self.0 as f64 * 0.67),
(self.0 as f64 * 0.90) as u8, round_u8(self.0 as f64 * 0.90),
) )
} }
/// Lighten this color by a factor. /// Lighten this color by a factor.
pub fn lighten(self, factor: f64) -> Self { pub fn lighten(self, factor: Ratio) -> Self {
Self(self.0.saturating_add(((u8::MAX - self.0) as f64 * factor) as u8)) let inc = round_u8((u8::MAX - self.0) as f64 * factor.get());
Self(self.0.saturating_add(inc))
} }
/// Darken this color by a factor. /// Darken this color by a factor.
pub fn darken(self, factor: f64) -> Self { pub fn darken(self, factor: Ratio) -> Self {
Self(self.0.saturating_sub((self.0 as f64 * factor) as u8)) let dec = round_u8(self.0 as f64 * factor.get());
Self(self.0.saturating_sub(dec))
} }
/// Negate this color. /// Negate this color.
@ -182,12 +180,12 @@ impl RgbaColor {
Self { r, g, b, a } Self { r, g, b, a }
} }
// Lighten this color by a factor. /// Lighten this color by a factor.
// ///
// The alpha channel is not affected. /// The alpha channel is not affected.
pub fn lighten(self, factor: f64) -> Self { pub fn lighten(self, factor: Ratio) -> Self {
let lighten = |c: u8| c.saturating_add(((u8::MAX - c) as f64 * factor) as u8); let lighten =
|c: u8| c.saturating_add(round_u8((u8::MAX - c) as f64 * factor.get()));
Self { Self {
r: lighten(self.r), r: lighten(self.r),
g: lighten(self.g), g: lighten(self.g),
@ -196,12 +194,11 @@ impl RgbaColor {
} }
} }
// Darken this color by a factor. /// Darken this color by a factor.
// ///
// The alpha channel is not affected. /// The alpha channel is not affected.
pub fn darken(self, factor: f64) -> Self { pub fn darken(self, factor: Ratio) -> Self {
let darken = |c: u8| c.saturating_sub((c as f64 * factor) as u8); let darken = |c: u8| c.saturating_sub(round_u8(c as f64 * factor.get()));
Self { Self {
r: darken(self.r), r: darken(self.r),
g: darken(self.g), g: darken(self.g),
@ -210,9 +207,9 @@ impl RgbaColor {
} }
} }
// Negate this color. /// Negate this color.
// ///
// The alpha channel is not affected. /// The alpha channel is not affected.
pub fn negate(self) -> Self { pub fn negate(self) -> Self {
Self { Self {
r: u8::MAX - self.r, r: u8::MAX - self.r,
@ -242,13 +239,11 @@ impl FromStr for RgbaColor {
let long = len == 6 || len == 8; let long = len == 6 || len == 8;
let short = len == 3 || len == 4; let short = len == 3 || len == 4;
let alpha = len == 4 || len == 8; let alpha = len == 4 || len == 8;
if !long && !short { if !long && !short {
return Err("string has wrong length"); return Err("string has wrong length");
} }
let mut values: [u8; 4] = [u8::MAX; 4]; let mut values: [u8; 4] = [u8::MAX; 4];
for elem in if alpha { 0 .. 4 } else { 0 .. 3 } { for elem in if alpha { 0 .. 4 } else { 0 .. 3 } {
let item_len = if long { 2 } else { 1 }; let item_len = if long { 2 } else { 1 };
let pos = elem * item_len; let pos = elem * item_len;
@ -323,10 +318,10 @@ impl CmykColor {
/// Convert this color to RGBA. /// Convert this color to RGBA.
pub fn to_rgba(self) -> RgbaColor { pub fn to_rgba(self) -> RgbaColor {
let k = self.k as f32 / 255.0; let k = self.k as f64 / 255.0;
let f = |c| { let f = |c| {
let c = c as f32 / 255.0; let c = c as f64 / 255.0;
(255.0 * (1.0 - c) * (1.0 - k)).round() as u8 round_u8(255.0 * (1.0 - c) * (1.0 - k))
}; };
RgbaColor { RgbaColor {
@ -338,9 +333,8 @@ impl CmykColor {
} }
/// Lighten this color by a factor. /// Lighten this color by a factor.
pub fn lighten(self, factor: f64) -> Self { pub fn lighten(self, factor: Ratio) -> Self {
let lighten = |c: u8| c.saturating_sub((c as f64 * factor) as u8); let lighten = |c: u8| c.saturating_sub(round_u8(c as f64 * factor.get()));
Self { Self {
c: lighten(self.c), c: lighten(self.c),
m: lighten(self.m), m: lighten(self.m),
@ -350,9 +344,9 @@ impl CmykColor {
} }
/// Darken this color by a factor. /// Darken this color by a factor.
pub fn darken(self, factor: f64) -> Self { pub fn darken(self, factor: Ratio) -> Self {
let darken = |c: u8| c.saturating_add(((u8::MAX - c) as f64 * factor) as u8); let darken =
|c: u8| c.saturating_add(round_u8((u8::MAX - c) as f64 * factor.get()));
Self { Self {
c: darken(self.c), c: darken(self.c),
m: darken(self.m), m: darken(self.m),
@ -412,6 +406,11 @@ impl Default for Stroke {
} }
} }
/// Convert to the closest u8.
fn round_u8(value: f64) -> u8 {
value.round() as u8
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -23,7 +23,7 @@
--- ---
// Test gray color modification. // Test gray color modification.
#test(luma(20%).lighten(50%), luma(60%)) #test(luma(20%).lighten(50%), luma(60%))
#test(luma(80%).darken(20%), luma(64.5%)) #test(luma(80%).darken(20%), luma(63.9%))
#test(luma(80%).negate(), luma(20%)) #test(luma(80%).negate(), luma(20%))
--- ---