Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix CMYK from-conversion and add it as possible color function #200

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/cli/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
\n - 789\
\n - 'rgb(119, 136, 153)'\
\n - '119,136,153'\
\n - 'hsl(210, 14.3%, 53.3%)'\n\
\n - 'hsl(210, 14.3%, 53.3%)'\
\n - 'cmyk(22, 11, 0, 40)'\n\
Alpha transparency is also supported:\
\n - '#77889980'\
\n - 'rgba(119, 136, 153, 0.5)'\
Expand All @@ -38,7 +39,7 @@
.short('s')
.value_name("name")
.help("The colorspace in which to interpolate")
.possible_values(&["Lab", "LCh", "RGB", "HSL", "OkLab"])

Check warning on line 42 in src/cli/cli.rs

View workflow job for this annotation

GitHub Actions / Code quality

the borrowed expression implements the required traits
.ignore_case(true)
.default_value("Lab");

Expand Down Expand Up @@ -95,7 +96,7 @@
\n\
Default strategy: 'vivid'\n ",
)
.possible_values(&["vivid", "rgb", "gray", "lch_hue"])

Check warning on line 99 in src/cli/cli.rs

View workflow job for this annotation

GitHub Actions / Code quality

the borrowed expression implements the required traits
.hide_default_value(true)
.hide_possible_values(true)
.default_value("vivid"),
Expand Down Expand Up @@ -131,7 +132,7 @@
.help("Distance metric to compute mutual color distances. The CIEDE2000 is \
more accurate, but also much slower.")
.takes_value(true)
.possible_values(&["CIEDE2000", "CIE76"])

Check warning on line 135 in src/cli/cli.rs

View workflow job for this annotation

GitHub Actions / Code quality

the borrowed expression implements the required traits
.value_name("name")
.default_value("CIE76")
)
Expand Down Expand Up @@ -211,7 +212,7 @@
.help("Output format type. Note that the 'ansi-*-escapecode' formats print \
ansi escape sequences to the terminal that will not be visible \
unless something else is printed in addition.")
.possible_values(&["rgb", "rgb-float", "hex",

Check warning on line 215 in src/cli/cli.rs

View workflow job for this annotation

GitHub Actions / Code quality

the borrowed expression implements the required traits
"hsl", "hsl-hue", "hsl-saturation", "hsl-lightness",
"hsv", "hsv-hue", "hsv-saturation", "hsv-value",
"lch", "lch-lightness", "lch-chroma", "lch-hue",
Expand Down Expand Up @@ -340,7 +341,7 @@
Arg::new("type")
.help("The type of colorblindness that should be simulated (protanopia, \
deuteranopia, tritanopia)")
.possible_values(&["prot", "deuter", "trit"])

Check warning on line 344 in src/cli/cli.rs

View workflow job for this annotation

GitHub Actions / Code quality

the borrowed expression implements the required traits
.ignore_case(true)
.required(true),
)
Expand All @@ -355,7 +356,7 @@
.arg(
Arg::new("property")
.help("The property that should be changed")
.possible_values(&["lightness", "hue", "chroma",

Check warning on line 359 in src/cli/cli.rs

View workflow job for this annotation

GitHub Actions / Code quality

the borrowed expression implements the required traits
"lab-a", "lab-b",
"oklab-l", "oklab-a", "oklab-b",
"red", "green", "blue",
Expand Down Expand Up @@ -490,7 +491,7 @@
.short('m')
.value_name("mode")
.help("Specify the terminal color mode: 24bit, 8bit, off, *auto*")
.possible_values(&["24bit", "8bit", "off", "auto"])

Check warning on line 494 in src/cli/cli.rs

View workflow job for this annotation

GitHub Actions / Code quality

the borrowed expression implements the required traits
.default_value(if output_vt100::try_init().is_ok() {"auto"} else {"off"})
.hide_possible_values(true)
.hide_default_value(true)
Expand Down
16 changes: 5 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -960,11 +960,11 @@ impl From<&LCh> for Color {
impl From<&CMYK> for Color {
fn from(color: &CMYK) -> Self {
#![allow(clippy::many_single_char_names)]
let r = 255.0 * ((1.0 - color.c) / 100.0) * ((1.0 - color.k) / 100.0);
let g = 255.0 * ((1.0 - color.m) / 100.0) * ((1.0 - color.k) / 100.0);
let b = 255.0 * ((1.0 - color.y) / 100.0) * ((1.0 - color.k) / 100.0);
let r = Scalar::round(255.0 * (1.0 - color.c / 100.0) * (1.0 - color.k / 100.0)) as u8;
let g = Scalar::round(255.0 * (1.0 - color.m / 100.0) * (1.0 - color.k / 100.0)) as u8;
let b = Scalar::round(255.0 * (1.0 - color.y / 100.0) * (1.0 - color.k / 100.0)) as u8;
Comment on lines +963 to +965
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the other color spaces, we have tests that make sure that we can convert e.g. HSL -> Lab -> HSL and get the same color back. You can search for roundtrip in this file to see some examples. It would be great if we could add tests for CMYK, too.


Color::from(&RGBA::<f64> {
Color::from(&RGBA::<u8> {
r,
g,
b,
Expand Down Expand Up @@ -1429,13 +1429,7 @@ impl From<&Color> for CMYK {
let r = (rgba.r as f64) / 255.0;
let g = (rgba.g as f64) / 255.0;
let b = (rgba.b as f64) / 255.0;
let biggest = if r >= g && r >= b {
r
} else if g >= r && g >= b {
g
} else {
b
};
let biggest = r.max(g).max(b);
let out_k = 1.0 - biggest;
let out_c = (1.0 - r - out_k) / biggest;
let out_m = (1.0 - g - out_k) / biggest;
Expand Down
29 changes: 29 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,24 @@ fn parse_numeric_rgb(input: &str) -> IResult<&str, Color> {
Ok((input, c))
}

fn parse_cmyk(input: &str) -> IResult<&str, Color> {
let (input, _) = tag("cmyk(")(input)?;
let (input, _) = space0(input)?;
let (input, c) = double(input)?;
let (input, _) = parse_separator(input)?;
let (input, m) = double(input)?;
let (input, _) = parse_separator(input)?;
let (input, y) = double(input)?;
let (input, _) = parse_separator(input)?;
let (input, k) = double(input)?;
let (input, _) = space0(input)?;
let (input, _) = char(')')(input)?;

let color = Color::from_cmyk(c, m, y, k);

Ok((input, color))
}

fn parse_percentage_rgb(input: &str) -> IResult<&str, Color> {
let (input, prefixed) = opt(alt((tag("rgb("), tag("rgba("))))(input)?;
let is_prefixed = prefixed.is_some();
Expand Down Expand Up @@ -284,6 +302,7 @@ pub fn parse_color(input: &str) -> Option<Color> {
all_consuming(parse_hex),
all_consuming(parse_numeric_rgb),
all_consuming(parse_percentage_rgb),
all_consuming(parse_cmyk),
all_consuming(parse_hsl),
all_consuming(parse_hsv),
all_consuming(parse_gray),
Expand Down Expand Up @@ -380,6 +399,16 @@ fn parse_rgb_standalone_syntax() {
assert_eq!(Some(rgb(1, 2, 3)), parse_color("1,2,3"));
}

#[test]
fn parse_cmyk_syntax() {
assert_eq!(Some(Color::black()), parse_color("cmyk(0, 0, 0, 100)"));
assert_eq!(Some(Color::white()), parse_color("cmyk(0, 0, 0, 0)"));
assert_eq!(Some(Color::red()), parse_color("cmyk(0, 100, 100, 0)"));
assert_eq!(Some(Color::green()), parse_color("cmyk(100, 0, 100, 50)"));
assert_eq!(Some(Color::blue()), parse_color("cmyk(100, 100,0,0)"));
assert_eq!(Some(Color::yellow()), parse_color("cmyk( 0,0, 100, 0)"));
}

#[test]
fn parse_hsl_syntax() {
assert_eq!(
Expand Down
Loading