diff -Nru rust-colorsys-0.5.7/Cargo.toml rust-colorsys-0.6.5/Cargo.toml --- rust-colorsys-0.5.7/Cargo.toml 2020-09-27 19:56:41.000000000 +0000 +++ rust-colorsys-0.6.5/Cargo.toml 1970-01-01 00:00:01.000000000 +0000 @@ -3,24 +3,28 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. [package] -edition = "2018" +edition = "2021" name = "colorsys" -version = "0.5.7" +version = "0.6.5" authors = ["mz "] -description = "Module for convert and transform colors" +description = "A module for color conversion and mutation. Works with RGB(a)( as hexadecimal too), HSL(a), CMYK color models and with ANSI color codes" homepage = "https://github.com/emgyrz/colorsys.rs" readme = "README.md" -keywords = ["colors", "converter", "css", "rgb", "hsl"] +keywords = ["colors", "converter", "rgb", "hsl", "cmyk"] categories = ["graphics"] license = "MIT" repository = "https://github.com/emgyrz/colorsys.rs.git" +resolver = "2" [dependencies] + +[features] +default = ["std"] +std = [] diff -Nru rust-colorsys-0.5.7/Cargo.toml.orig rust-colorsys-0.6.5/Cargo.toml.orig --- rust-colorsys-0.5.7/Cargo.toml.orig 2020-09-27 19:32:48.000000000 +0000 +++ rust-colorsys-0.6.5/Cargo.toml.orig 1973-11-29 21:33:09.000000000 +0000 @@ -1,14 +1,19 @@ [package] name = "colorsys" -version = "0.5.7" -description = "Module for convert and transform colors" +version = "0.6.5" +description = "A module for color conversion and mutation. Works with RGB(a)( as hexadecimal too), HSL(a), CMYK color models and with ANSI color codes" authors = ["mz "] license = "MIT" homepage = "https://github.com/emgyrz/colorsys.rs" repository = "https://github.com/emgyrz/colorsys.rs.git" -keywords = ["colors", "converter", "css", "rgb", "hsl"] +keywords = ["colors", "converter", "rgb", "hsl", "cmyk"] categories = [ "graphics"] -edition = "2018" +edition = "2021" readme = "README.md" [dependencies] + + +[features] +default = [ "std" ] +std = [] diff -Nru rust-colorsys-0.5.7/.cargo_vcs_info.json rust-colorsys-0.6.5/.cargo_vcs_info.json --- rust-colorsys-0.5.7/.cargo_vcs_info.json 2020-09-27 19:56:41.000000000 +0000 +++ rust-colorsys-0.6.5/.cargo_vcs_info.json 1970-01-01 00:00:01.000000000 +0000 @@ -1,5 +1,5 @@ { "git": { - "sha1": "201eab30c8247c275080a8702c0b1da99b258fd7" + "sha1": "b5d1fe27b9b8f7d8c9975b12ec80b8d69bce2ed8" } } diff -Nru rust-colorsys-0.5.7/debian/cargo-checksum.json rust-colorsys-0.6.5/debian/cargo-checksum.json --- rust-colorsys-0.5.7/debian/cargo-checksum.json 2020-11-01 11:43:39.000000000 +0000 +++ rust-colorsys-0.6.5/debian/cargo-checksum.json 2022-06-14 22:44:59.000000000 +0000 @@ -1 +1 @@ -{"package":"be475c891fad1522a7bfd1cb7204ba8e8fe48a93a0ad6992356aca07a4e0cbce","files":{}} +{"package":"Could not get crate checksum","files":{}} diff -Nru rust-colorsys-0.5.7/debian/changelog rust-colorsys-0.6.5/debian/changelog --- rust-colorsys-0.5.7/debian/changelog 2020-11-01 11:43:39.000000000 +0000 +++ rust-colorsys-0.6.5/debian/changelog 2022-06-14 22:44:59.000000000 +0000 @@ -1,3 +1,11 @@ +rust-colorsys (0.6.5-1) unstable; urgency=medium + + * Team upload. + * Package colorsys 0.6.5 from crates.io using debcargo 2.5.0 + * Fix tests with --no-default-features. + + -- Peter Michael Green Tue, 14 Jun 2022 22:44:59 +0000 + rust-colorsys (0.5.7-1) unstable; urgency=medium * Package colorsys 0.5.7 from crates.io using debcargo 2.4.3 diff -Nru rust-colorsys-0.5.7/debian/compat rust-colorsys-0.6.5/debian/compat --- rust-colorsys-0.5.7/debian/compat 2020-11-01 11:43:39.000000000 +0000 +++ rust-colorsys-0.6.5/debian/compat 2022-06-14 22:44:59.000000000 +0000 @@ -1 +1 @@ -11 +12 diff -Nru rust-colorsys-0.5.7/debian/control rust-colorsys-0.6.5/debian/control --- rust-colorsys-0.5.7/debian/control 2020-11-01 11:43:39.000000000 +0000 +++ rust-colorsys-0.6.5/debian/control 2022-06-14 22:44:59.000000000 +0000 @@ -1,18 +1,19 @@ Source: rust-colorsys Section: rust Priority: optional -Build-Depends: debhelper (>= 11), - dh-cargo (>= 18), +Build-Depends: debhelper (>= 12), + dh-cargo (>= 25), cargo:native , rustc:native , libstd-rust-dev Maintainer: Debian Rust Maintainers Uploaders: Stephan Lachnit -Standards-Version: 4.4.1 +Standards-Version: 4.5.1 Vcs-Git: https://salsa.debian.org/rust-team/debcargo-conf.git [src/colorsys] Vcs-Browser: https://salsa.debian.org/rust-team/debcargo-conf/tree/master/src/colorsys Homepage: https://github.com/emgyrz/colorsys.rs +Rules-Requires-Root: no Package: librust-colorsys-dev Architecture: any @@ -21,12 +22,19 @@ ${misc:Depends} Provides: librust-colorsys+default-dev (= ${binary:Version}), + librust-colorsys+std-dev (= ${binary:Version}), librust-colorsys-0-dev (= ${binary:Version}), librust-colorsys-0+default-dev (= ${binary:Version}), - librust-colorsys-0.5-dev (= ${binary:Version}), - librust-colorsys-0.5+default-dev (= ${binary:Version}), - librust-colorsys-0.5.7-dev (= ${binary:Version}), - librust-colorsys-0.5.7+default-dev (= ${binary:Version}) -Description: Module for convert and transform colors - Rust source code + librust-colorsys-0+std-dev (= ${binary:Version}), + librust-colorsys-0.6-dev (= ${binary:Version}), + librust-colorsys-0.6+default-dev (= ${binary:Version}), + librust-colorsys-0.6+std-dev (= ${binary:Version}), + librust-colorsys-0.6.5-dev (= ${binary:Version}), + librust-colorsys-0.6.5+default-dev (= ${binary:Version}), + librust-colorsys-0.6.5+std-dev (= ${binary:Version}) +Description: Module for color conversion and mutation - Rust source code + Works with RGB(a)( as hexadecimal too), HSL(a), CMYK color models and with ANSI + color codes + . This package contains the source for the Rust colorsys crate, packaged by debcargo for use with cargo and dh-cargo. diff -Nru rust-colorsys-0.5.7/debian/copyright rust-colorsys-0.6.5/debian/copyright --- rust-colorsys-0.5.7/debian/copyright 2020-11-01 11:43:39.000000000 +0000 +++ rust-colorsys-0.6.5/debian/copyright 2022-06-14 22:44:59.000000000 +0000 @@ -4,12 +4,12 @@ Source: https://github.com/emgyrz/colorsys.rs.git Files: * -Copyright: 2019 Max Z +Copyright: 2019-2021 Max Z License: MIT Files: debian/* Copyright: - 2020 Debian Rust Maintainers + 2020-2022 Debian Rust Maintainers 2020 Stephan Lachnit License: MIT diff -Nru rust-colorsys-0.5.7/debian/copyright.debcargo.hint rust-colorsys-0.6.5/debian/copyright.debcargo.hint --- rust-colorsys-0.5.7/debian/copyright.debcargo.hint 2020-11-01 11:43:39.000000000 +0000 +++ rust-colorsys-0.6.5/debian/copyright.debcargo.hint 2022-06-14 22:44:59.000000000 +0000 @@ -21,8 +21,8 @@ Files: debian/* Copyright: - 2020 Debian Rust Maintainers - 2020 Stephan Lachnit + 2020-2022 Debian Rust Maintainers + 2020-2022 Stephan Lachnit License: MIT License: MIT diff -Nru rust-colorsys-0.5.7/debian/patches/fix-tests-no-default-features.patch rust-colorsys-0.6.5/debian/patches/fix-tests-no-default-features.patch --- rust-colorsys-0.5.7/debian/patches/fix-tests-no-default-features.patch 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/debian/patches/fix-tests-no-default-features.patch 2022-06-14 22:44:59.000000000 +0000 @@ -0,0 +1,114 @@ +Index: colorsys/src/converters/rgb_to_hsl.rs +=================================================================== +--- colorsys.orig/src/converters/rgb_to_hsl.rs ++++ colorsys/src/converters/rgb_to_hsl.rs +@@ -46,6 +46,7 @@ fn rgb_to_hsl_tst() { + fn a(x: ColorTuple, y: ColorTuple) -> bool { + let from_rgb_u = rgb_to_hsl(&Rgb::from(x)); + let hsl_u = new_hsl_units(y.0, y.1, y.2); ++ #[cfg(feature = "std")] + println!("rgb {:?}\n\n", Into::::into(Rgb::from(x))); + from_rgb_u.approx_eq_clarify(&hsl_u, 0.5) + // Rgb::from(x).approx_eq_clarify(&Hsl::from(y), 0.5) +Index: colorsys/src/units/iter.rs +=================================================================== +--- colorsys.orig/src/units/iter.rs ++++ colorsys/src/units/iter.rs +@@ -39,6 +39,8 @@ impl core::iter::Iterator for ColorUnits + #[cfg(test)] + mod test { + use crate::Rgb; ++ #[cfg(not(feature = "std"))] ++ use alloc::vec::Vec; + + #[test] + fn color_iter_collect_test() { +Index: colorsys/src/common/mod.rs +=================================================================== +--- colorsys.orig/src/common/mod.rs ++++ colorsys/src/common/mod.rs +@@ -34,5 +34,7 @@ pub(crate) fn f64_round(n: f64) -> f64 { + } + #[cfg(not(feature = "std"))] + pub(crate) fn f64_round(n: f64) -> f64 { +- f64::from(n as i32) ++ let adjustment = if n < 0.0 {-0.5} else {0.5}; ++ ++ f64::from((n+adjustment) as i32) + } +Index: colorsys/src/hsl/tests.rs +=================================================================== +--- colorsys.orig/src/hsl/tests.rs ++++ colorsys/src/hsl/tests.rs +@@ -13,11 +13,11 @@ fn round_tuple(t: &ColorTuple) -> (u32, + fn hsl_to_rgb() { + let hsl = Hsl::from((126.0, 43.0, 52.0)); + let rgb = Rgb::from(&hsl); +- #[cfg(feature = "std")] ++ //#[cfg(feature = "std")] + assert_eq!(round_tuple(&rgb.as_ref().into()), (80, 185, 90)); + +- #[cfg(not(feature = "std"))] +- assert_eq!(round_tuple(&rgb.as_ref().into()), (79, 185, 90)); ++ /*#[cfg(not(feature = "std"))] ++ assert_eq!(round_tuple(&rgb.as_ref().into()), (79, 185, 90));*/ + + let hsl_new = Hsl::from(&rgb); + assert!(hsl_new.approx_eq(&hsl)); +Index: colorsys/src/rgb/tests.rs +=================================================================== +--- colorsys.orig/src/rgb/tests.rs ++++ colorsys/src/rgb/tests.rs +@@ -19,20 +19,20 @@ fn lighten() { + + rgb.lighten(15.0); + +- #[cfg(feature = "std")] ++ //#[cfg(feature = "std")] + assert_eq!(round_tuple(&rgb.into()), (135, 208, 142)); +- #[cfg(not(feature = "std"))] +- assert_eq!(round_tuple(&rgb.into()), (134, 207, 141)); ++ //#[cfg(not(feature = "std"))] ++ //assert_eq!(round_tuple(&rgb.into()), (134, 207, 141)); + + rgb2.lighten(45.0); +- #[cfg(feature = "std")] ++ //#[cfg(feature = "std")] + assert_eq!(round_tuple(&rgb2.into()), (245, 251, 245)); +- #[cfg(not(feature = "std"))] +- assert_eq!(round_tuple(&rgb2.into()), (244, 250, 245)); ++ //#[cfg(not(feature = "std"))] ++ //assert_eq!(round_tuple(&rgb2.into()), (244, 250, 245)); + + + rgb3.lighten(-23.0); +- #[cfg(feature = "std")] ++ //#[cfg(feature = "std")] + assert_eq!(round_tuple(&rgb3.into()), (42, 107, 48)); + + rgb4.lighten(-203.0); +Index: colorsys/src/rgb/transform.rs +=================================================================== +--- colorsys.orig/src/rgb/transform.rs ++++ colorsys/src/rgb/transform.rs +@@ -80,15 +80,15 @@ mod test { + } + + let asserts = [ +- #[cfg(feature = "std")] ++// #[cfg(feature = "std")] + ((30.0, 108.0, 77.0), 20.0, (52, 188, 134)), + ((30.0, 108.0, 77.0), 90.0, (255, 255, 255)), +- #[cfg(feature = "std")] ++// #[cfg(feature = "std")] + ((30.0, 108.0, 77.0), -20.0, (8, 28, 20)), +- #[cfg(feature = "std")] ++// #[cfg(feature = "std")] + ((0.0, 0.0, 0.0), 50.0, (128, 128, 128)), +- #[cfg(not(feature = "std"))] +- ((0.0, 0.0, 0.0), 50.0, (127, 127, 127)), ++// #[cfg(not(feature = "std"))] ++// ((0.0, 0.0, 0.0), 50.0, (127, 127, 127)), + ((0.0, 0.0, 0.0), -50.0, (0, 0, 0)), + ((0.0, 0.0, 0.0), 300.5, (255, 255, 255)), + ]; diff -Nru rust-colorsys-0.5.7/debian/patches/series rust-colorsys-0.6.5/debian/patches/series --- rust-colorsys-0.5.7/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/debian/patches/series 2022-06-14 22:44:59.000000000 +0000 @@ -0,0 +1 @@ +fix-tests-no-default-features.patch diff -Nru rust-colorsys-0.5.7/debian/tests/control rust-colorsys-0.6.5/debian/tests/control --- rust-colorsys-0.5.7/debian/tests/control 2020-11-01 11:43:39.000000000 +0000 +++ rust-colorsys-0.6.5/debian/tests/control 2022-06-14 22:44:59.000000000 +0000 @@ -1,9 +1,19 @@ -Test-Command: /usr/share/cargo/bin/cargo-auto-test colorsys 0.5.7 --all-targets --all-features -Features: test-name=@ +Test-Command: /usr/share/cargo/bin/cargo-auto-test colorsys 0.6.5 --all-targets --all-features +Features: test-name=rust-colorsys:@ Depends: dh-cargo (>= 18), @ Restrictions: allow-stderr, skip-not-installable -Test-Command: /usr/share/cargo/bin/cargo-auto-test colorsys 0.5.7 --all-targets --no-default-features -Features: test-name=librust-colorsys-dev +Test-Command: /usr/share/cargo/bin/cargo-auto-test colorsys 0.6.5 --all-targets +Features: test-name=librust-colorsys-dev:default +Depends: dh-cargo (>= 18), @ +Restrictions: allow-stderr, skip-not-installable + +Test-Command: /usr/share/cargo/bin/cargo-auto-test colorsys 0.6.5 --all-targets --no-default-features --features std +Features: test-name=librust-colorsys-dev:std +Depends: dh-cargo (>= 18), @ +Restrictions: allow-stderr, skip-not-installable + +Test-Command: /usr/share/cargo/bin/cargo-auto-test colorsys 0.6.5 --all-targets --no-default-features +Features: test-name=librust-colorsys-dev: Depends: dh-cargo (>= 18), @ Restrictions: allow-stderr, skip-not-installable diff -Nru rust-colorsys-0.5.7/README.md rust-colorsys-0.6.5/README.md --- rust-colorsys-0.5.7/README.md 2020-09-27 19:32:48.000000000 +0000 +++ rust-colorsys-0.6.5/README.md 1973-11-29 21:33:09.000000000 +0000 @@ -2,20 +2,25 @@ [![Crates.io](https://img.shields.io/crates/v/colorsys.svg)](https://crates.io/crates/colorsys/) -A module for color conversion and mutation written in Rust. For now works with RGB(a)( as hexadecimal too), HSL(a) color models +A module for color conversion and mutation written in Rust. +For now works with next color models: + - RGB(a)( as hexadecimal too) + - HSL(a) + - CMYK(a) + - ANSI256 codes -[Online documentation](https://docs.rs/colorsys/0.5.7/colorsys/) +[Documentation](https://docs.rs/colorsys) ## What It Can Do #### getters & setters -```Rust -use colorsys::{Rgb, Hsl}; +```rust +use colorsys::{Rgb, Hsl, ColorAlpha}; let rgb = Rgb::from((57.3, 12.7, 53.0)); -let r = rgb.get_red(); +let r = rgb.red(); // 57.3 let mut hsl = Hsl::default(); @@ -28,7 +33,7 @@ #### conversion See `From/FromStr/Into` traits implementation in docs for more info -```Rust +```rust use colorsys::{Rgb, Hsl}; let rbga_tuple = (57.3, 12.7, 53.0, 0.33); @@ -36,7 +41,7 @@ let hsla: Hsl = rgba.as_ref().into(); // ~Hsl { h: 305.78, s: 63.71, l: 13.73, a: 0.33 } -let rgb_arr: [u8, u8, u8] = Rgb::from(&hsla).into(); +let rgb_arr: [u8; 3] = Rgb::from(&hsla).into(); // ~[57, 13, 53] let hsla_tuple: (f64,f64,f64,f64) = Hsl::from( Rgb::from(rgb_tuple) ).into(); @@ -52,7 +57,7 @@ let rgb2 = Rgb::from( Into::<[f32; 4]>::into(Rgb::from( - Into::<[u8; 4]>::into( + Into::<[u8; 3]>::into( Rgb::from( Into::<(i32,i32,i32)>::into( Rgb::from( @@ -82,7 +87,7 @@ #### modification See `ColorTransform/Add*/Sub*..` traits in docs for more -```Rust +```rust use colorsys::{Hsl, Rgb, ColorTransform,ColorAlpha, SaturationInSpace}; let mut rgb: Rgb = (245.0,152.0,53.0).into(); @@ -120,7 +125,7 @@ ``` #### parsing from string & css string representation -```Rust +```rust use colorsys::{Hsl, Rgb}; use std::str::FromStr; @@ -139,20 +144,29 @@ ``` +## `no_std` +Crate has a Cargo feature named `"std"` that is enabled by default. +In order to use `colorsys` in a `no_std` context this feature needs to be disabled. +Modify your dependency to opt out of enabled-by-default features. +```toml +[dependencies] +colorsys = { version = "*", default-features = false } +``` + ## Color unit ranges All color units is f64. Here are their ranges: - - red - 0.0 .. 255.0 - - green - 0.0 .. 255.0 - - blue - 0.0 .. 255.0 - - hue - 0.0 .. 360.0 - - saturation - 0.0 .. 100.0 - - lightness - 0.0 .. 100.0 - - alpha - 0.0 .. 1.0 - -If you specify a value that does not fit within these ranges, they are replaced with a minimum or maximum value. - + - red: 0.0 - 255.0 + - green: 0.0 - 255.0 + - blue: 0.0 - 255.0 + - hue: 0.0 - 360.0 + - saturation: 0.0 - 100.0 + - lightness: 0.0 - 100.0 + - all in cmyk are: 0.0 - 100.0 + - alpha: 0.0 - 1.0 + - ansi256 code is `u8` +If you specify a value that does not fit within these ranges, they are replaced with a minimum or maximum value. ##### Enjoy using! diff -Nru rust-colorsys-0.5.7/src/ansi/mod.rs rust-colorsys-0.6.5/src/ansi/mod.rs --- rust-colorsys-0.5.7/src/ansi/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/src/ansi/mod.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,136 @@ +use crate::Rgb; + +/// Predefined set of 256 colors to use with ANSI escape sequences, +/// e.g. in terminal emulators +/// +/// # Example +/// ``` +/// use colorsys::{Ansi256, Rgb}; +/// +/// let rgb = Rgb::from_hex_str("#875fff").unwrap(); +/// let ansi256: Ansi256 = rgb.into(); +/// assert_eq!(ansi256.code(),99); +/// +/// let green_yellow = Ansi256::new(154); +/// let rgb2 = green_yellow.as_rgb(); +/// assert_eq!(rgb2.to_hex_string(), "#afff00"); +/// +/// let txt = format!( +/// "\x1b[38;5;{ansi_code}m{text}\x1b[0m", +/// ansi_code=green_yellow.code(), +/// text="my colored text" +/// ); +/// println!("{}", txt); +/// +/// ``` +#[derive(Debug, Copy, Clone)] +pub struct Ansi256(pub(crate) u8); + +impl Ansi256 { + pub fn new(ansi_code: u8) -> Self { + Ansi256(ansi_code) + } + pub fn code(&self) -> u8 { + self.0 + } + pub fn set_code(&mut self, v: u8) { + self.0 = v; + } + + pub fn as_rgb(&self) -> Rgb { + (*self).into() + } +} + + +impl From<&Rgb> for Ansi256 { + fn from(rgb: &Rgb) -> Self { + let [r, g, b]: [u8; 3] = rgb.into(); + let red = if r < 75 { 0 } else { (r - 35) / 40 }; + let green = if g < 75 { 0 } else { (g - 35) / 40 }; + let blue = if b < 75 { 0 } else { (b - 35) / 40 }; + Ansi256(red * 6 * 6 + green * 6 + blue + 16) + } +} + + +impl From for Ansi256 { + fn from(rgb: Rgb) -> Self { + rgb.as_ref().into() + } +} + + +impl From for Rgb { + fn from(ansi256: Ansi256) -> Self { + let code = ansi256.0; + if code < 16 { + let mut base = code; + let mut mul = 128; + if code == 7 { mul = 192; } else if code == 8 { base = 7; } else if code > 8 { mul = 255; } + let r = (base & 1) * mul; + let g = ((base & 2) >> 1) * mul; + let b = ((base & 4) >> 2) * mul; + Rgb::from((r, g, b)) + + } else if code > 231 { + let gray = (code - 232) * 10 + 8; + Rgb::from((gray, gray, gray)) + + } else { + let b = (code - 16) % 6; + let b = if b == 0 { 0 } else { b * 40 + 55 }; + + let g = ((code - 16) / 6) % 6; + let g = if g == 0 { 0 } else { g * 40 + 55 }; + + let r = (code - 16) / 36; + let r = if r == 0 { 0 } else { r * 40 + 55 }; + + Rgb::from((r, g, b)) + } + } +} + + +#[cfg(test)] +mod test { + use crate::ansi::Ansi256; + use crate::Rgb; + + #[test] + fn rgb_to_ansi_test() { + let test_data = [ + ([95u8,0,175], 55u8), + ([135,95,255], 99), + ([135,255,255], 123), + ([215,175,95], 179), + ([255,215,255], 225), + ]; + for (rgb_arr, ansi_code) in &test_data { + let ansi: Ansi256 = Rgb::from(rgb_arr).as_ref().into(); + assert_eq!(ansi.code(), *ansi_code); + } + } + + #[test] + fn ansi_to_rgb_test() { + let test_data = [ + (9u8, [255u8, 0, 0]), + (211, [255,135,175]), + (187, [215,215,175]), + (171, [215,95,255]), + (77, [95,215,95]), + (0, [0,0,0]), + (13, [255,0,255]), + (249, [178,178,178]), + ]; + for (ansi_code, rgb_arr) in &test_data { + let rgb: Rgb = Ansi256(*ansi_code).into(); + let arr: [u8;3] = rgb.into(); + assert_eq!(&arr, rgb_arr); + } + + } +} + diff -Nru rust-colorsys-0.5.7/src/cmyk/from.rs rust-colorsys-0.6.5/src/cmyk/from.rs --- rust-colorsys-0.5.7/src/cmyk/from.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/src/cmyk/from.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,109 @@ +use crate::{Cmyk, Rgb}; +use crate::cmyk::CmykRatio; +use crate::consts::PERCENT_MAX; +use crate::converters::{cmyk_to_rgb, rgb_to_cmyk}; + +fn cmyk_from_ratio(r: &CmykRatio) -> Cmyk { + let mut u = r.units.clone(); + for v in &mut u.list { + v.turn_into_whole(&PERCENT_MAX); + } + Cmyk::from_units(u) +} + +impl From<&CmykRatio> for Cmyk { + fn from(r: &CmykRatio) -> Self { + cmyk_from_ratio(r) + } +} + +impl From<&mut CmykRatio> for Cmyk { + fn from(r: &mut CmykRatio) -> Self { + cmyk_from_ratio(r) + } +} + +impl From for Cmyk { + fn from(r: CmykRatio) -> Self { + cmyk_from_ratio(&r) + } +} + + +fn cmyk_to_ratio(cmyk: &Cmyk) -> CmykRatio { + CmykRatio::from_units(cmyk.units.as_ratio()) +} + +impl From<&Cmyk> for CmykRatio { + fn from(r: &Cmyk) -> Self { + cmyk_to_ratio(r) + } +} + +impl From<&mut Cmyk> for CmykRatio { + fn from(r: &mut Cmyk) -> Self { + cmyk_to_ratio(r) + } +} + +impl From for CmykRatio { + fn from(r: Cmyk) -> Self { + cmyk_to_ratio(&r) + } +} + + +impl From<&mut Rgb> for Cmyk { + fn from(rgb: &mut Rgb) -> Self { + rgb_to_cmyk(rgb) + } +} + +impl From<&Rgb> for Cmyk { + fn from(rgb: &Rgb) -> Self { + rgb_to_cmyk(rgb) + } +} + +impl From for Cmyk { + fn from(rgb: Rgb) -> Self { + rgb_to_cmyk(&rgb) + } +} + + +impl From<&mut Cmyk> for Rgb { + fn from(cmyk: &mut Cmyk) -> Self { + cmyk_to_rgb(cmyk) + } +} + +impl From<&Cmyk> for Rgb { + fn from(cmyk: &Cmyk) -> Self { + cmyk_to_rgb(cmyk) + } +} + +impl From for Rgb { + fn from(cmyk: Cmyk) -> Self { + cmyk_to_rgb(&cmyk) + } +} + + +impl From<[f64; 4]> for Cmyk { + fn from(a: [f64; 4]) -> Self { Cmyk::new(a[0], a[1], a[2], a[3], None) } +} + +impl<'a> From<&'a [f64; 4]> for Cmyk { + fn from(a: &[f64; 4]) -> Self { Cmyk::new(a[0], a[1], a[2], a[3], None) } +} + + +impl Into<[f64; 4]> for Cmyk { + fn into(self: Cmyk) -> [f64; 4] { self.units.into() } +} + +impl<'a> Into<[f64; 4]> for &'a Cmyk { + fn into(self) -> [f64; 4] { self.units.clone().into() } +} \ No newline at end of file diff -Nru rust-colorsys-0.5.7/src/cmyk/mod.rs rust-colorsys-0.6.5/src/cmyk/mod.rs --- rust-colorsys-0.5.7/src/cmyk/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/src/cmyk/mod.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,106 @@ +use core::ops::{Add, AddAssign, Sub, SubAssign}; + +pub use ratio::CmykRatio; + +use crate::consts::PERCENT_MAX; +use crate::Rgb; +use crate::units::{Alpha, GetColorUnits, Unit, Units}; + +mod ratio; +mod from; + + +/// The CMYK color model. +/// +/// Has cyan, magenta, yellow, key (0.0..100.0) and optional `alpha` channel (0.0..1.0). +/// +/// # Example +/// ``` +/// use colorsys::Cmyk; +/// +/// let mut cmyk = Cmyk::new(33.1, 999.9, 11.0, 0.0, None); +/// +/// assert_eq!(cmyk.cyan(), 33.1); +/// assert_eq!(cmyk.magenta(), 100.0); +/// +/// cmyk.set_yellow(73.0); +/// assert_eq!(cmyk.yellow(), 73.0); +/// +/// let doubled_cmyk = &cmyk + &cmyk; +/// +/// let units: [f64;4] = doubled_cmyk.into(); +/// assert_eq!(units, [66.2,100.0,100.0,0.0]); +/// +/// ``` +#[derive(Debug, PartialEq, Clone)] +pub struct Cmyk { + pub(crate) units: Units, +} +ops_def!(Cmyk); + + +pub(crate) fn new_cmyk_units(c: f64, m: f64, y: f64, k: f64) -> Units { + let p = |v: f64| Unit::new_percent(v); + let ul = [p(c), p(m), p(y), p(k)]; + Units { len: 4, list: ul, alpha: Alpha::default() } +} + +impl Cmyk { + pub fn new(c: f64, m: f64, y: f64, k: f64, a: Option) -> Self { + let mut u = new_cmyk_units(c, m, y, k); + u.alpha.set_opt(a); + u.restrict(); + Cmyk::from_units(u) + } + + pub fn cyan(&self) -> f64 { self.units[0] } + pub fn magenta(&self) -> f64 { self.units[1] } + pub fn yellow(&self) -> f64 { self.units[2] } + pub fn key(&self) -> f64 { self.units[3] } + + pub fn set_cyan(&mut self, c: f64) { self.units.list[0].set(c); } + pub fn set_magenta(&mut self, m: f64) { self.units.list[1].set(m); } + pub fn set_yellow(&mut self, y: f64) { self.units.list[2].set(y); } + pub fn set_key(&mut self, k: f64) { self.units.list[3].set(k); } + + /// Returns same color in RGB color model + /// # Example + /// ``` + /// use colorsys::{Cmyk, Rgb, ApproxEq}; + /// + /// let cmyk = Cmyk::from(&[0.0,0.0,100.0,0.0]); + /// let rgb_from_cmyk = cmyk.as_rgb(); + /// assert!(rgb_from_cmyk.approx_eq(&Rgb::from([255,255,0]))); + /// + /// ``` + pub fn as_rgb(&self) -> Rgb { + self.into() + } + pub fn as_ratio(&self) -> CmykRatio { + self.into() + } + + pub(crate) fn from_units(u: Units) -> Cmyk { + Cmyk { units: u } + } +} + + +impl GetColorUnits for Cmyk { + fn get_units(&self) -> &Units { &self.units } + fn get_units_mut(&mut self) -> &mut Units { &mut self.units } +} + + +impl AsRef for Cmyk { + fn as_ref(&self) -> &Cmyk { self } +} + +impl Default for Cmyk { + fn default() -> Cmyk { + Cmyk::from_units(new_cmyk_units(0.0, 0.0, 0.0, PERCENT_MAX)) + } +} + + + diff -Nru rust-colorsys-0.5.7/src/cmyk/ratio.rs rust-colorsys-0.6.5/src/cmyk/ratio.rs --- rust-colorsys-0.5.7/src/cmyk/ratio.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/src/cmyk/ratio.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,66 @@ +use crate::units::Units; + +#[derive(Debug, PartialEq, Clone)] +pub struct CmykRatio { + pub(crate) units: Units, +} + +impl CmykRatio { + pub fn new(c: f64, m: f64, y: f64, k: f64, a: f64) -> Self { + let mut u = Units::new_ratios(&[c, m, y, k]); + u.alpha.set(a); + CmykRatio::from_units(u) + } + + pub fn cyan(&self) -> f64 { self.units[0] } + pub fn magenta(&self) -> f64 { self.units[1] } + pub fn yellow(&self) -> f64 { self.units[2] } + pub fn key(&self) -> f64 { self.units[3] } + + pub fn set_cyan(&mut self, c: f64) { self.units.list[0].set(c); } + pub fn set_magenta(&mut self, m: f64) { self.units.list[1].set(m); } + pub fn set_yellow(&mut self, y: f64) { self.units.list[2].set(y); } + pub fn set_key(&mut self, k: f64) { self.units.list[3].set(k); } + + pub(crate) fn from_units(u: Units) -> Self { + CmykRatio { units: u } + } +} + + +impl AsRef for CmykRatio { + fn as_ref(&self) -> &CmykRatio { self } +} + +impl Default for CmykRatio { + fn default() -> CmykRatio { + CmykRatio::new(0.0, 0.0, 0.0, 1.0, 1.0) + } +} + +impl From<[f64; 4]> for CmykRatio { + fn from(a: [f64; 4]) -> Self { CmykRatio::new(a[0], a[1], a[2], a[3], 1.0) } +} + +impl<'a> From<&'a [f64; 4]> for CmykRatio { + fn from(a: &[f64; 4]) -> Self { CmykRatio::new(a[0], a[1], a[2], a[3], 1.0) } +} + +impl Into<[f64; 4]> for CmykRatio { + fn into(self: CmykRatio) -> [f64; 4] { self.units.into() } +} +impl<'a> Into<[f64; 4]> for &'a CmykRatio { + fn into(self) -> [f64; 4] { self.units.clone().into() } +} + +#[cfg(test)] +mod test { + use crate::{Cmyk, Rgb}; + use crate::converters::cmyk_to_rgb; + + #[test] + fn cmyk_to_rbg_test() { + let cmyk = Cmyk::new(30.0, 30.0, 30.0, 30.0, None); + let _rgb: Rgb = cmyk_to_rgb(&cmyk); + } +} diff -Nru rust-colorsys-0.5.7/src/common/alpha.rs rust-colorsys-0.6.5/src/common/alpha.rs --- rust-colorsys-0.5.7/src/common/alpha.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/src/common/alpha.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,45 @@ +use crate::units::GetColorUnits; + +/// Methods to work with alpha channel in color. +pub trait ColorAlpha { + /// Returns alpha channel. If it not set will returns 1.0 + fn alpha(&self) -> f64; + /// Returns alpha channel. If it not set will returns 1.0 + #[deprecated(since = "0.7.0", note = "Please use `alpha` instead")] + fn get_alpha(&self) -> f64; + + /// Sets alpha channel + /// ``` + /// use colorsys::{Hsl,ColorAlpha}; + /// let mut hsl = Hsl::default(); // Hsl { a: None, .. } + /// hsl.set_alpha(0.45); // Hsl { a: 0.45, .. } + /// hsl.set_alpha(123.015); // Hsl { a: 1.0, .. } + /// hsl.set_alpha(-123.3); // Hsl { a: 0.0, .. } + /// ``` + fn set_alpha(&mut self, val: f64); + + /// Increase/decrease color alpha channel with specified value. Value can be negative. + /// # Example + /// ``` + /// use colorsys::{Hsl,ColorAlpha}; + /// let mut hsl = Hsl::default(); // Hsl { a: None, .. } + /// hsl.opacify(-0.3); // Hsl { a: 0.7, .. } + /// hsl.opacify(0.015); // Hsl { a: 0.715, .. } + /// ``` + fn opacify(&mut self, val: f64); +} + + + +impl ColorAlpha for T where T: GetColorUnits { + fn alpha(&self) -> f64 { self.get_units().alpha.get_f64() } + fn get_alpha(&self) -> f64 { + self.alpha() + } + fn set_alpha(&mut self, val: f64) { + self.get_units_mut().alpha.set(val); + } + fn opacify(&mut self, val: f64) { + self.get_units_mut().alpha.opacify(val); + } +} diff -Nru rust-colorsys-0.5.7/src/common/approx.rs rust-colorsys-0.6.5/src/common/approx.rs --- rust-colorsys-0.5.7/src/common/approx.rs 2020-09-27 19:37:33.000000000 +0000 +++ rust-colorsys-0.6.5/src/common/approx.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,4 +1,5 @@ -use crate::ColorTuple; +use crate::common::f64_abs; +use crate::units::GetColorUnits; /// Default precision used for color comparison. /// It is `0.000_000_001` @@ -11,18 +12,14 @@ } pub fn approx(x: f64, y: f64, precision: f64) -> bool { - (x - y).abs() < precision -} -pub fn approx_def(x: f64, y: f64) -> bool { - approx(x, y, DEFAULT_APPROX_EQ_PRECISION) -} - -pub fn approx_tuple(x: &ColorTuple, y: &ColorTuple, precision: f64) -> bool { - approx(x.0, y.0, precision) - && approx(x.1, y.1, precision) - && approx(x.2, y.2, precision) + f64_abs(x - y) < precision } -pub fn approx_tuple_def(x: &ColorTuple, y: &ColorTuple) -> bool { - approx_def(x.0, y.0) && approx_def(x.1, y.1) && approx_def(x.2, y.2) +impl ApproxEq for T where T: GetColorUnits { + fn approx_eq(&self, other: &T) -> bool { + self.get_units().approx_eq(other.get_units()) + } + fn approx_eq_clarify(&self, other: &T, precision: f64) -> bool { + self.get_units().approx_eq_clarify(other.get_units(), precision) + } } diff -Nru rust-colorsys-0.5.7/src/common/from_str.rs rust-colorsys-0.6.5/src/common/from_str.rs --- rust-colorsys-0.5.7/src/common/from_str.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/src/common/from_str.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,71 @@ +// static RGB_START: &[u8; 3] = b"rgb"; +// static HSL_START: &[u8; 3] = b"rgb"; +// static COMMA: u8 = b','; +// static DOT: u8 = b'.'; +// +// fn is_delimiter(ch: u8) -> bool { +// ch.is_ascii_whitespace() || ch == COMMA +// } +// fn is_val_char(ch: u8) -> bool { +// ch.is_ascii_digit() || ch == DOT +// } +// +// fn from_bytes(bytes: &[u8]) -> Result<([f64; 4], usize), ()> { +// let bytes_len = bytes.len(); +// if bytes_len == 0 { return Err(()) } +// let mut buff = [0.0; 4]; +// let mut buff_len = 0; +// +// let mut i = 0; +// while i < bytes_len { +// let ch = bytes[i]; +// if !is_val_char(ch) { +// i += 1; +// continue +// } +// +// let mut chi = i + 1; +// while chi < bytes_len && is_val_char(bytes[chi]) { +// chi += 1; +// } +// let s = core::str::from_utf8(&bytes[i..chi]).map_err(|_| ())?; +// if buff_len == 4 { return Err(()) } +// buff[buff_len] = s.parse().map_err(|_| ())?; +// buff_len += 1; +// i = chi + 1; +// } +// +// if buff_len == 0 { return Err(()) } +// +// Ok((buff, buff_len)) +// } +// +// +// #[allow(clippy::float_cmp)] +// #[cfg(test)] +// mod test { +// use crate::common::from_str::from_bytes; +// +// #[test] +// fn collect_digits_from_str_test() { +// let valid = [ +// ("10,30,40", [10.0f64, 30.0, 40.0, 0.0]), +// ("10.5,30, 400.1, 22", [10.5, 30.0, 400.1, 22.0]), +// ("rgb( 0,30, 400.1, 22) ", [0.0, 30.0, 400.1, 22.0]), +// ("1.33 ", [1.33, 0.0, 0.0, 0.0]), +// ]; +// let invalid = [ +// "", +// "asd", +// "rgb( 0,30, 400.1, 22, 1) " +// ]; +// +// for (s, arr) in &valid { +// assert_eq!(&from_bytes(s.as_bytes()).unwrap().0, arr); +// } +// +// for s in &invalid { +// assert!(&from_bytes(s.as_bytes()).is_err()); +// } +// } +// } \ No newline at end of file diff -Nru rust-colorsys-0.5.7/src/common/hsv_hsl_from_str.rs rust-colorsys-0.6.5/src/common/hsv_hsl_from_str.rs --- rust-colorsys-0.5.7/src/common/hsv_hsl_from_str.rs 2020-09-27 19:38:05.000000000 +0000 +++ rust-colorsys-0.6.5/src/common/hsv_hsl_from_str.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,3 +1,7 @@ + +#[cfg(not(feature = "std"))] use alloc::string::String; +#[cfg(not(feature = "std"))] use alloc::vec::Vec; + use super::Hs; use crate::err::{make_parse_err, ParseError}; use crate::{consts, ColorTuple}; diff -Nru rust-colorsys-0.5.7/src/common/iter.rs rust-colorsys-0.6.5/src/common/iter.rs --- rust-colorsys-0.5.7/src/common/iter.rs 2020-08-26 20:25:36.000000000 +0000 +++ rust-colorsys-0.6.5/src/common/iter.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -use crate::ColorTuple; - -pub struct ColorIter { - ind: usize, - vals: [Option; 4], -} - -impl ColorIter { - pub fn from_tuple_w_alpha(t: ColorTuple, a: Option) -> ColorIter { - ColorIter { ind: 0, vals: [Some(t.0), Some(t.1), Some(t.2), a] } - } -} - -impl std::iter::Iterator for ColorIter { - type Item = f64; - fn next(&mut self) -> Option { - match self.ind { - 0...3 => { - let val = self.vals[self.ind]; - self.ind += 1; - val - } - _ => None, - } - } -} diff -Nru rust-colorsys-0.5.7/src/common/mod.rs rust-colorsys-0.6.5/src/common/mod.rs --- rust-colorsys-0.5.7/src/common/mod.rs 2020-08-26 20:25:36.000000000 +0000 +++ rust-colorsys-0.6.5/src/common/mod.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,26 +1,38 @@ -// use std::time::{SystemTime, UNIX_EPOCH}; +pub use alpha::ColorAlpha; +pub use hsv_hsl_from_str::hsl_hsv_from_str; +pub use tuple_to_string::tuple_to_string; + +pub use crate::units::iter::ColorUnitsIter; mod hsv_hsl_from_str; -mod iter; mod tuple_to_string; +mod alpha; +mod from_str; pub mod approx; -pub mod ops; - -pub use hsv_hsl_from_str::hsl_hsv_from_str; -pub use iter::ColorIter; -pub use tuple_to_string::tuple_to_string; pub enum Hs { + #[allow(dead_code)] Hsv, + Hsl, } -// pub fn simple_rand(max: f64) -> f64 { -// let num = vec![1, 2, 3]; -// let address = &num as *const Vec; -// let num = f64::from((address as i32).abs()); - -// let nanos = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().subsec_nanos(); -// (f64::from(nanos) * num) % max -// } + +#[cfg(feature = "std")] +pub(crate) fn f64_abs(n: f64) -> f64 { + n.abs() +} +#[cfg(not(feature = "std"))] +pub(crate) fn f64_abs(n: f64) -> f64 { + if n < 0.0 { -n } else { n } +} + +#[cfg(feature = "std")] +pub(crate) fn f64_round(n: f64) -> f64 { + n.round() +} +#[cfg(not(feature = "std"))] +pub(crate) fn f64_round(n: f64) -> f64 { + f64::from(n as i32) +} diff -Nru rust-colorsys-0.5.7/src/common/ops.rs rust-colorsys-0.6.5/src/common/ops.rs --- rust-colorsys-0.5.7/src/common/ops.rs 2020-08-26 20:25:36.000000000 +0000 +++ rust-colorsys-0.6.5/src/common/ops.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -use crate::ColorTuple; - -type Op = Option; -type TupleA = (ColorTuple, Op); - -pub fn add_sub_alpha(a1: &Op, a2: &Op, is_add: bool) -> Op { - let has1 = a1.is_some(); - let has2 = a2.is_some(); - if !has1 && !has2 { - return None; - } else if has1 && has2 { - let val1 = a1.unwrap(); - let val2 = a2.unwrap(); - let val = if is_add { val1 + val2 } else { val1 - val2 }; - return Some(val); - } - - if has1 { - *a1 - } else { - *a2 - } -} - -pub fn add_sub_tuples( - t1: &ColorTuple, - t2: &ColorTuple, - is_add: bool, -) -> ColorTuple { - let (x1, y1, z1) = t1; - let (x2, y2, z2) = t2; - - if is_add { - (x1 + x2, y1 + y2, z1 + z2) - } else { - (x1 - x2, y1 - y2, z1 - z2) - } -} - -pub fn add_sub_tuples_a(ta1: &TupleA, ta2: &TupleA, is_add: bool) -> TupleA { - let (t1, a1) = ta1; - let (t2, a2) = ta2; - - let t = add_sub_tuples(t1, t2, is_add); - let a = add_sub_alpha(a1, a2, is_add); - (t, a) -} diff -Nru rust-colorsys-0.5.7/src/common/tuple_to_string.rs rust-colorsys-0.6.5/src/common/tuple_to_string.rs --- rust-colorsys-0.5.7/src/common/tuple_to_string.rs 2020-08-26 20:25:36.000000000 +0000 +++ rust-colorsys-0.6.5/src/common/tuple_to_string.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,32 +1,37 @@ +#[cfg(not(feature = "std"))] use alloc::string::String; use crate::{normalize::round_ratio, ColorTupleA}; +use crate::common::{f64_abs, f64_round}; pub fn tuple_to_string(tuple: &ColorTupleA, prefix: &str) -> String { let (x, y, z, a) = tuple; let mut start = String::from(prefix); - let a = if (a - 1.0).abs() < std::f64::EPSILON { + let a = if f64_abs(a - 1.0) < core::f64::EPSILON { String::from("1") } else { - round_ratio(*a).to_string() + format!("{}", round_ratio(*a)) }; let is_hsl = prefix == "hsl"; - let mut vals = [x, y, z] + let mut result = String::new(); + [x, y, z] .iter() .enumerate() - .map(|(ind, u)| { - let mut s = u.round().to_string(); + .for_each(|(ind, u)| { + result.push_str(&format!("{}", f64_round(**u))); if is_hsl && (ind == 1 || ind == 2) { - s.push('%'); + result.push('%'); } - s - }) - .collect::>() - .join(","); + if ind != 2 { + result.push(','); + } + }); if a != "1" { start.push('a'); - vals.push_str(&(",".to_owned() + &a)); + result.push(','); + result.push_str(&a); } - format!("{}({})", start, vals) + format!("{}({})", start, result) } + diff -Nru rust-colorsys-0.5.7/src/converters/hex_to_rgb.rs rust-colorsys-0.6.5/src/converters/hex_to_rgb.rs --- rust-colorsys-0.5.7/src/converters/hex_to_rgb.rs 2020-08-26 20:25:36.000000000 +0000 +++ rust-colorsys-0.6.5/src/converters/hex_to_rgb.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,31 +1,93 @@ -use crate::{err, ColorTuple}; +#[cfg(not(feature = "std"))] +use alloc::string::String; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + use err::{make_parse_err, ParseError}; -pub fn hex_to_rgb(s: &str) -> Result { - let mut hex = s.replace("#", "").to_lowercase(); - let hex_chars = hex.chars().collect::>(); - let count = hex_chars.len(); - - if count == 3 { - hex = hex_chars - .iter() - .map(|c| c.to_string().repeat(2)) - .collect::>() - .join(""); - } else if count != 6 { - return Err(make_parse_err(s, "hex")); +use crate::err; + +const HASH: u8 = b'#'; + + +pub(crate) fn hex_to_rgb(s: &str) -> Result<[u32; 3], ParseError> { + from_hex(s.as_bytes()).map_err(|_| make_parse_err(s, "hex")) +} + +pub(crate) fn from_hex(s: &[u8]) -> Result<[u32; 3], ()> { + let mut buff: [u8; 6] = [0; 6]; + let mut buff_len = 0; + + + for b in s { + if !b.is_ascii() || buff_len == 6 { + return Err(()); + } + + let bl = b.to_ascii_lowercase(); + if bl == HASH { continue } + if bl.is_ascii_hexdigit() { + buff[buff_len] = bl; + buff_len += 1; + } } - match usize::from_str_radix(&hex, 16) { - Ok(num) => Ok(hex_num_to_rgb(num)), - Err(_) => Err(make_parse_err(s, "hex")), + if buff_len == 3 { + buff = [buff[0], buff[0], buff[1], buff[1], buff[2], buff[2]]; } + + let hex_str = core::str::from_utf8(&buff).map_err(|_| ())?; + let hex_digit = u32::from_str_radix(hex_str, 16).map_err(|_| ())?; + + Ok(hex_digit_to_rgb(hex_digit)) } -fn hex_num_to_rgb(num: usize) -> ColorTuple { - let r = (num >> 16) as f64; - let g = ((num >> 8) & 0x00FF) as f64; - let b = (num & 0x0000_00FF) as f64; - (r, g, b) +fn hex_digit_to_rgb(num: u32) -> [u32; 3] { + let r = num >> 16; + let g = (num >> 8) & 0x00FF; + let b = num & 0x0000_00FF; + + [r, g, b] +} + +#[cfg(test)] +mod test { + use crate::converters::hex_to_rgb::{from_hex, hex_to_rgb}; + + #[test] + fn from_hex_test() { + let valid = [ + ("000", [0u32; 3]), + ("#000", [0; 3]), + ("#000000", [0; 3]), + ("fFf", [255; 3]), + ("#fff", [255; 3]), + ("#ffFfff", [255; 3]), + ("#ffffff", [255; 3]), + ("#777", [119; 3]), + ("F7b3aA", [247, 179, 170]) + ]; + + let invalid = [ + "0000", + "#0000f221", + "#000000a", + "ั‚ะตัั‚", + "ffccfg", + "", + ]; + + for (s, t) in valid.iter() { + let rgb = from_hex(s.as_bytes()).unwrap(); + assert_eq!(&rgb, t); + } + + for s in invalid.iter() { + let result = from_hex(s.as_bytes()); + assert!(result.is_err()); + } + } } + + diff -Nru rust-colorsys-0.5.7/src/converters/hsl_to_rgb.rs rust-colorsys-0.6.5/src/converters/hsl_to_rgb.rs --- rust-colorsys-0.5.7/src/converters/hsl_to_rgb.rs 2020-08-26 20:25:36.000000000 +0000 +++ rust-colorsys-0.6.5/src/converters/hsl_to_rgb.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,7 +1,8 @@ use crate::consts::RGB_UNIT_MAX; +use crate::Hsl; use crate::normalize::bound_ratio; -use crate::ratio_converters::hsl_to_ratio; -use crate::ColorTuple; +use crate::rgb::new_rgb_units; +use crate::units::Units; static ONE: f64 = 1.0; static TWO: f64 = 2.0; @@ -10,23 +11,11 @@ static ONE_THIRD: f64 = ONE / 3.0; static TWO_THIRD: f64 = TWO / 3.0; -pub fn hsl_to_rgb(hsl: &ColorTuple) -> ColorTuple { - let calc_rgb_unit = |unit: f64, temp1: f64, temp2: f64| -> f64 { - let mut result = temp2; - if SIX * unit < ONE { - result = temp2 + (temp1 - temp2) * SIX * unit - } else if TWO * unit < ONE { - result = temp1 - } else if 3.0 * unit < TWO { - result = temp2 + (temp1 - temp2) * (TWO_THIRD - unit) * SIX - } - result * RGB_UNIT_MAX - }; - - let (h, s, l) = hsl_to_ratio(hsl); +pub(crate) fn hsl_to_rgb(hsl: &Hsl) -> Units { + let [h, s, l]: [f64; 3] = hsl.units.as_ratio().into(); if s == 0.0 { let unit = RGB_UNIT_MAX * l; - return (unit, unit, unit); + return new_rgb_units(unit, unit, unit); } let temp1 = if l < 0.5 { l * (ONE + s) } else { l + s - l * s }; @@ -41,18 +30,39 @@ let r = calc_rgb_unit(temp_r, temp1, temp2); let g = calc_rgb_unit(temp_g, temp1, temp2); let b = calc_rgb_unit(temp_b, temp1, temp2); - (r, g, b) + new_rgb_units(r, g, b) } -#[test] -fn hsl_to_rgb_tst() { - use crate::common::approx::approx_tuple; - fn a(x: ColorTuple, y: ColorTuple) -> bool { - approx_tuple(&hsl_to_rgb(&x), &y, 0.5) +fn calc_rgb_unit(unit: f64, temp1: f64, temp2: f64) -> f64 { + let mut result = temp2; + if SIX * unit < ONE { + result = temp2 + (temp1 - temp2) * SIX * unit + } else if TWO * unit < ONE { + result = temp1 + } else if 3.0 * unit < TWO { + result = temp2 + (temp1 - temp2) * (TWO_THIRD - unit) * SIX } + result * RGB_UNIT_MAX +} + - assert!(a((200.0, 100.0, 30.0), (0.0, 102.0, 153.0))); - assert!(a((192.0, 67.0, 28.0), (24.0, 100.0, 119.0))); - assert!(a((48.0, 70.0, 50.0), (217.0, 181.0, 38.0))); - assert!(a((359.0, 33.0, 77.0), (216.0, 177.0, 178.0))); +#[cfg(test)] +mod test { + use crate::{ApproxEq, ColorTuple, Hsl, Rgb}; + + #[test] + fn hsl_to_rgb_tst() { + use crate::converters::hsl_to_rgb; + + fn a(x: ColorTuple, y: ColorTuple) -> bool { + let hsl = Hsl::from(x); + let rgb = Rgb::from(y); + hsl_to_rgb(&hsl).approx_eq_clarify(&rgb.units, 0.5) + } + + assert!(a((200.0, 100.0, 30.0), (0.0, 102.0, 153.0))); + assert!(a((192.0, 67.0, 28.0), (24.0, 100.0, 119.0))); + assert!(a((48.0, 70.0, 50.0), (217.0, 181.0, 38.0))); + assert!(a((359.0, 33.0, 77.0), (216.0, 177.0, 178.0))); + } } diff -Nru rust-colorsys-0.5.7/src/converters/mod.rs rust-colorsys-0.6.5/src/converters/mod.rs --- rust-colorsys-0.5.7/src/converters/mod.rs 2019-07-26 21:09:06.000000000 +0000 +++ rust-colorsys-0.6.5/src/converters/mod.rs 1973-11-29 21:33:09.000000000 +0000 @@ -2,8 +2,10 @@ mod hsl_to_rgb; mod rgb_to_hex; mod rgb_to_hsl; +mod rgb_cmyk; -pub use hex_to_rgb::hex_to_rgb; -pub use hsl_to_rgb::hsl_to_rgb; -pub use rgb_to_hex::rgb_to_hex; -pub use rgb_to_hsl::rgb_to_hsl; +pub(crate) use hex_to_rgb::hex_to_rgb; +pub(crate) use hsl_to_rgb::hsl_to_rgb; +pub(crate) use rgb_to_hex::rgb_to_hex; +pub(crate) use rgb_to_hsl::rgb_to_hsl; +pub(crate) use rgb_cmyk::{rgb_to_cmyk, cmyk_to_rgb}; diff -Nru rust-colorsys-0.5.7/src/converters/rgb_cmyk.rs rust-colorsys-0.6.5/src/converters/rgb_cmyk.rs --- rust-colorsys-0.5.7/src/converters/rgb_cmyk.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/src/converters/rgb_cmyk.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,56 @@ +use crate::{Cmyk, Rgb}; +use crate::cmyk::CmykRatio; +use crate::consts::{RATIO_MAX, RGB_UNIT_MAX}; + +pub(crate) fn rgb_to_cmyk(rgb: &Rgb) -> Cmyk { + let rgb_r = rgb.units.as_ratio(); + let [ r, g, b ]: [f64; 3] = (&rgb_r).into(); + let k = RATIO_MAX - rgb_r.max().0; + let x = RATIO_MAX - k; + + let c = (x - r) / x; + let m = (x - g) / x; + let y = (x - b) / x; + + CmykRatio::new(c, m, y, k, rgb.units.alpha.get_f64()).into() +} + +pub(crate) fn cmyk_to_rgb(cmyk: &Cmyk) -> Rgb { + let [ c, m, y, k ]: [f64;4] = cmyk.units.as_ratio().into(); + let x = RGB_UNIT_MAX * (1.0 - k); + + Rgb::new((1.0 - c) * x, (1.0 - m) * x, (1.0 - y) * x, cmyk.units.alpha.get()) +} + +#[allow(clippy::float_cmp)] +#[cfg(test)] +mod test { + use crate::{Cmyk, Rgb}; + use crate::converters::{cmyk_to_rgb, rgb_to_cmyk}; + + #[test] + fn cmyk_to_rbg_test() { + let cmyk = Cmyk::new(70.0, 23.0, 11.0, 55.0, None); + let rgb: Rgb = cmyk_to_rgb(&cmyk); + assert_eq!(rgb.units[0].round(), 34.0); + assert_eq!(rgb.units[1].round(), 88.0); + assert_eq!(rgb.units[2].round(), 102.0); + } + + #[test] + fn rbg_to_cmyk_test() { + // let assert_data = [ + // ([35, 75, 89], [61, 16, 0, 65]), + // ([0, 0, 255], [100, 100, 0, 0]), + // ([0, 0, 0], [0, 0, 0, 100]), + // ([255, 255, 255], [0, 0, 0, 0]), + // ]; + + let rgb = Rgb::new(230.0, 19.0, 70.0, None); + let cmyk: Cmyk = rgb_to_cmyk(&rgb); + assert_eq!(cmyk.cyan().round(), 0.0); + assert_eq!(cmyk.magenta().round(), 92.0); + assert_eq!(cmyk.yellow().round(), 70.0); + assert_eq!(cmyk.key().round(), 10.0); + } +} diff -Nru rust-colorsys-0.5.7/src/converters/rgb_to_hex.rs rust-colorsys-0.6.5/src/converters/rgb_to_hex.rs --- rust-colorsys-0.5.7/src/converters/rgb_to_hex.rs 2020-08-26 20:25:36.000000000 +0000 +++ rust-colorsys-0.6.5/src/converters/rgb_to_hex.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,9 +1,13 @@ + +#[cfg(not(feature = "std"))] use alloc::string::String; + use crate::ColorTuple; +use crate::common::f64_round; fn to_hex(n: f64) -> String { - let s = format!("{:x}", n.round() as u32); + let s = format!("{:x}", f64_round(n) as u32); if s.len() == 1 { - "0".to_string() + &s + String::from("0") + &s } else { s } diff -Nru rust-colorsys-0.5.7/src/converters/rgb_to_hsl.rs rust-colorsys-0.6.5/src/converters/rgb_to_hsl.rs --- rust-colorsys-0.5.7/src/converters/rgb_to_hsl.rs 2020-09-27 19:39:57.000000000 +0000 +++ rust-colorsys-0.6.5/src/converters/rgb_to_hsl.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,43 +1,18 @@ +use crate::Rgb; use crate::consts::{ALL_MIN, PERCENT_MAX}; -use crate::ratio_converters::rgb_to_ratio; -use crate::ColorTuple; +use crate::hsl::new_hsl_units; +use crate::units::Units; -enum RgbUnit { - Red, - Green, - Blue, -} - -fn get_max(red: f64, green: f64, blue: f64) -> (f64, RgbUnit) { - if (red > green) && (red > blue) { - return (red, RgbUnit::Red); - } - if green > blue { - (green, RgbUnit::Green) - } else { - (blue, RgbUnit::Blue) - } -} +pub fn rgb_to_hsl(rgb: &Rgb) -> Units { + let rgb_r = rgb.units.as_ratio(); -fn get_min(red: f64, green: f64, blue: f64) -> f64 { - if (red < green) && (red < blue) { - red - } else if green < blue { - green - } else { - blue - } -} - -pub fn rgb_to_hsl(rgb: &ColorTuple) -> ColorTuple { - let (red, green, blue) = rgb_to_ratio(&rgb); - let (max, max_unit) = get_max(red, green, blue); - let min = get_min(red, green, blue); + let (max, max_unit) = rgb_r.max(); + let (min, _) = rgb_r.min(); let max_plus_min = max + min; let luminance = (max_plus_min) / 2.0; if max.eq(&min) { - return (ALL_MIN, ALL_MIN, luminance * PERCENT_MAX); + return new_hsl_units(ALL_MIN, ALL_MIN, luminance * PERCENT_MAX); } let max_min_delta = max - min; @@ -47,23 +22,34 @@ max_min_delta / (max_plus_min) }; + let [red, green, blue]: [f64; 3] = rgb_r.into(); + let hue = match max_unit { - RgbUnit::Red => { + // red + 0 => { let x = if green < blue { 6.0 } else { ALL_MIN }; (green - blue) / max_min_delta + x } - RgbUnit::Green => (blue - red) / max_min_delta + 2.0, - RgbUnit::Blue => (red - green) / max_min_delta + 4.0, + // green + 1 => (blue - red) / max_min_delta + 2.0, + // blue + 2 => (red - green) / max_min_delta + 4.0, + _ => { unreachable!() } }; - (hue * 60.0, saturation * PERCENT_MAX, luminance * PERCENT_MAX) + new_hsl_units(hue * 60.0, saturation * PERCENT_MAX, luminance * PERCENT_MAX) } #[test] fn rgb_to_hsl_tst() { - use crate::common::approx::approx_tuple; + use crate::{ColorTuple, Rgb, Hsl, ApproxEq}; fn a(x: ColorTuple, y: ColorTuple) -> bool { - approx_tuple(&rgb_to_hsl(&x), &y, 0.5) + let from_rgb_u = rgb_to_hsl(&Rgb::from(x)); + let hsl_u = new_hsl_units(y.0, y.1, y.2); + println!("rgb {:?}\n\n", Into::::into(Rgb::from(x))); + from_rgb_u.approx_eq_clarify(&hsl_u, 0.5) + // Rgb::from(x).approx_eq_clarify(&Hsl::from(y), 0.5) + // approx_tuple(&rgb_to_hsl(&Rgb::from(x)), &y, 0.5) } let asserts = [ ((255.0, 255.0, 255.0), (0.0, 0.0, 100.0)), diff -Nru rust-colorsys-0.5.7/src/err.rs rust-colorsys-0.6.5/src/err.rs --- rust-colorsys-0.5.7/src/err.rs 2020-08-26 20:25:36.000000000 +0000 +++ rust-colorsys-0.6.5/src/err.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,4 +1,5 @@ -use std::fmt; +use core::fmt; +#[cfg(not(feature = "std"))] use alloc::string::String; #[derive(Clone)] pub struct ParseError { @@ -25,4 +26,5 @@ ParseError { message: format!("cannot parse string `{}` as {}", s, col_type) } } +#[cfg(feature = "std")] impl std::error::Error for ParseError {} diff -Nru rust-colorsys-0.5.7/src/hsl/from.rs rust-colorsys-0.6.5/src/hsl/from.rs --- rust-colorsys-0.5.7/src/hsl/from.rs 2020-09-27 19:18:07.000000000 +0000 +++ rust-colorsys-0.6.5/src/hsl/from.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,8 +1,9 @@ -use super::{Hsl, HslRatio, Rgb}; use crate::{ - converters::*, ratio_converters::ratio_to_hsla, ColorAlpha, ColorTuple, + ColorAlpha, converters::*, ratio_converters::ratio_to_hsla, }; +use super::{Hsl, HslRatio, Rgb}; + macro_rules! from_for_hsl { ($from_type: ty, $val: ident, $conv: block) => { impl From<&$from_type> for Hsl { @@ -24,14 +25,19 @@ let (h, s, l) = *v; Hsl::new(h as f64, s as f64, l as f64, None) }); - from_for_hsl!(($t, $t, $t, $t), v, { - let (h, s, l, a) = *v; - Hsl::new(h as f64, s as f64, l as f64, Some(a as f64)) - }); from_for_hsl!([$t; 3], v, { let [h, s, l] = *v; Hsl::new(h as f64, s as f64, l as f64, None) }); + }; +} + +macro_rules! from_for_hsl_all_with_alpha { + ($t: ty) => { + from_for_hsl!(($t, $t, $t, $t), v, { + let (h, s, l, a) = *v; + Hsl::new(h as f64, s as f64, l as f64, Some(a as f64)) + }); from_for_hsl!([$t; 4], v, { let [h, s, l, a] = *v; Hsl::new(h as f64, s as f64, l as f64, Some(a as f64)) @@ -41,6 +47,8 @@ from_for_hsl_all!(f32); from_for_hsl_all!(f64); +from_for_hsl_all_with_alpha!(f32); +from_for_hsl_all_with_alpha!(f64); from_for_hsl_all!(i16); from_for_hsl_all!(i32); from_for_hsl_all!(i64); @@ -49,9 +57,8 @@ from_for_hsl_all!(u64); fn from_rgb(rgb: &Rgb) -> Hsl { - let a = rgb.get_alpha(); - let tuple: ColorTuple = rgb.into(); - let mut hsl = Hsl::from(rgb_to_hsl(&tuple)); + let a = rgb.alpha(); + let mut hsl = Hsl::from_units(rgb_to_hsl(rgb)); hsl.set_alpha(a); hsl } @@ -96,9 +103,11 @@ } fn from_hsl_ratio(ratio: &HslRatio) -> Hsl { - let t = ratio_to_hsla(&(ratio.h, ratio.s, ratio.l, ratio.a)); - Hsl { h: t.0, s: t.1, l: t.2, a: Some(t.3) } + let ru = &ratio.units; + let t = ratio_to_hsla(&(ru[0], ru[1], ru[2], ru.alpha.get_f64())); + Hsl::new(t.0, t.1, t.2, Some(t.3)) } + impl From<&HslRatio> for Hsl { fn from(r: &HslRatio) -> Self { from_hsl_ratio(r) @@ -126,26 +135,33 @@ macro_rules! into_for_hsl_all { ($t: ty) => { into_for_some!(($t, $t, $t), Hsl, self, { - let Hsl { h, s, l, .. } = *self; - (h as $t, s as $t, l as $t) - }); - into_for_some!(($t, $t, $t, $t), Hsl, self, { - let Hsl { h, s, l, .. } = *self; - (h as $t, s as $t, l as $t, self.get_alpha() as $t) + let u = &self.units; + (u[0] as $t, u[1] as $t, u[2] as $t) }); into_for_some!([$t; 3], Hsl, self, { - let Hsl { h, s, l, .. } = *self; - [h as $t, s as $t, l as $t] + let u = &self.units; + [u[0] as $t, u[1] as $t, u[2] as $t] + }); + }; +} + +macro_rules! into_for_hsl_all_with_alpha { + ($t: ty) => { + into_for_some!(($t, $t, $t, $t), Hsl, self, { + let u = &self.units; + (u[0] as $t, u[1] as $t, u[2] as $t, self.units.alpha.get_f64() as $t) }); into_for_some!([$t; 4], Hsl, self, { - let Hsl { h, s, l, .. } = *self; - [h as $t, s as $t, l as $t, self.get_alpha() as $t] + let u = &self.units; + [u[0] as $t, u[1] as $t, u[2] as $t, self.units.alpha.get_f64() as $t] }); }; } into_for_hsl_all!(f32); into_for_hsl_all!(f64); +into_for_hsl_all_with_alpha!(f32); +into_for_hsl_all_with_alpha!(f64); into_for_hsl_all!(i16); into_for_hsl_all!(i32); into_for_hsl_all!(i64); diff -Nru rust-colorsys-0.5.7/src/hsl/mod.rs rust-colorsys-0.6.5/src/hsl/mod.rs --- rust-colorsys-0.5.7/src/hsl/mod.rs 2020-09-27 18:19:57.000000000 +0000 +++ rust-colorsys-0.6.5/src/hsl/mod.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,81 +1,83 @@ +#[cfg(not(feature = "std"))] +use alloc::string::String; + pub use ratio::HslRatio; -use crate::common::{ - approx::approx_def, hsl_hsv_from_str, tuple_to_string, ColorIter, Hs, -}; -use crate::consts::RATIO_MAX; -use crate::normalize::{normalize_hue, normalize_percent, normalize_ratio}; -use crate::ratio_converters::hsla_to_ratio; -use crate::{ColorAlpha, ColorTuple, ColorTupleA, ParseError, Rgb}; +use crate::{ColorAlpha, ColorTupleA, ColorUnitsIter, ParseError, Rgb}; +use crate::common::{Hs, hsl_hsv_from_str, tuple_to_string, }; +use crate::units::{Alpha, GetColorUnits, Unit, Units}; #[cfg(test)] mod tests; mod from; -mod opts; +mod ops; mod ratio; mod transform; /// The HSL or HSI (hue, saturation, lightness (intensity)) color model /// /// Ranges: -/// * h (hue): 0.0 - 360.0 -/// * s (saturation): 0.0 - 100.0 -/// * l (saturation): 0.0 - 100.0 -/// * a (alpha): 0.0 - 1.0 +/// * hue: 0.0 - 360.0 +/// * saturation: 0.0 - 100.0 +/// * saturation: 0.0 - 100.0 +/// * alpha: 0.0 - 1.0 #[derive(Debug, PartialEq, Clone)] pub struct Hsl { - h: f64, - s: f64, - l: f64, - a: Option, + pub(crate) units: Units, } -impl Hsl { - fn _apply_tuple(&mut self, t: &ColorTuple) { - self.h = t.0; - self.s = t.1; - self.l = t.2; - } +iter_def!(Hsl); +pub(crate) fn new_hsl_units(h: f64, s: f64, l: f64) -> Units { + let ul = [Unit::new_hue(h), Unit::new_percent(s), Unit::new_percent(l), Unit::default()]; + Units { len: 3, list: ul, alpha: Alpha::default() } +} + +impl Hsl { pub fn new(h: f64, s: f64, l: f64, a: Option) -> Hsl { - let a = a.map(normalize_ratio).filter(|al| !approx_def(*al, RATIO_MAX)); - let np = normalize_percent; - Hsl { h: normalize_hue(h), s: np(s), l: np(l), a } + let mut units = new_hsl_units(h, s, l); + units.alpha.set_opt(a); + units.restrict(); + Hsl { units } } + pub(crate) fn from_units(u: Units) -> Self { Hsl { units: u } } + pub fn to_css_string(&self) -> String { let t: ColorTupleA = self.into(); tuple_to_string(&t, "hsl") } + pub fn hue(&self) -> f64 { self.units[0] } + pub fn saturation(&self) -> f64 { self.units[1] } + pub fn lightness(&self) -> f64 { self.units[2] } + + #[deprecated(since = "0.7.0", note = "Please use `hue` instead")] pub fn get_hue(&self) -> f64 { - self.h + self.hue() } + #[deprecated(since = "0.7.0", note = "Please use `saturation` instead")] pub fn get_saturation(&self) -> f64 { - self.s + self.saturation() } + #[deprecated(since = "0.7.0", note = "Please use `lightness` instead")] pub fn get_lightness(&self) -> f64 { - self.l + self.lightness() } - pub fn set_hue(&mut self, val: f64) { - self.h = normalize_hue(val); - } - pub fn set_saturation(&mut self, val: f64) { - self.s = normalize_percent(val); - } - pub fn set_lightness(&mut self, val: f64) { - self.l = normalize_percent(val); - } + pub fn set_hue(&mut self, val: f64) { self.units.list[0].set(val); } + pub fn set_saturation(&mut self, val: f64) { self.units.list[1].set(val); } + pub fn set_lightness(&mut self, val: f64) { self.units.list[2].set(val); } - pub fn iter(&self) -> ColorIter { - ColorIter::from_tuple_w_alpha(self.into(), self.a) + /// Returns an iterator over three color units and the possibly alpha value. + pub fn iter(&self) -> ColorUnitsIter { + ColorUnitsIter::from_units(&self.units) } + /// Returns an HSL representation with values converted to floar from 0.0 to 1.0 pub fn as_ratio(&self) -> HslRatio { - let t = hsla_to_ratio(&self.into()); - HslRatio { h: t.0, s: t.1, l: t.2, a: t.3 } + HslRatio::from_units(self.units.as_ratio()) } } @@ -86,7 +88,7 @@ // impl Default for Hsl { fn default() -> Hsl { - Hsl { h: 0.0, s: 0.0, l: 0.0, a: None } + Hsl::from_units(new_hsl_units(0.0, 0.0, 0.0)) } } @@ -97,7 +99,7 @@ // impl AsRef for Hsl { fn as_ref(&self) -> &Hsl { - &self + self } } @@ -106,7 +108,7 @@ // // FromStr // -impl std::str::FromStr for Hsl { +impl core::str::FromStr for Hsl { type Err = ParseError; fn from_str(s: &str) -> Result { let (tuple, alpha) = hsl_hsv_from_str(s, Hs::Hsl)?; @@ -118,42 +120,12 @@ } } -// -// -// -// ColorAlpha -// -impl ColorAlpha for Hsl { - fn get_alpha(&self) -> f64 { - self.a.unwrap_or(1.0) - } - - fn set_alpha(&mut self, val: f64) { - self.a = Some(normalize_ratio(val)); - } - fn opacify(&mut self, val: f64) { - self.set_alpha(self.get_alpha() + val); +impl GetColorUnits for Hsl { + fn get_units(&self) -> &Units { + &self.units } -} - -// -// -// -// Iter -// -impl<'a> std::iter::IntoIterator for &'a Hsl { - type Item = f64; - type IntoIter = ColorIter; - fn into_iter(self) -> ColorIter { - self.iter() - } -} - -impl std::iter::IntoIterator for Hsl { - type Item = f64; - type IntoIter = ColorIter; - fn into_iter(self) -> ColorIter { - self.iter() + fn get_units_mut(&mut self) -> &mut Units { + &mut self.units } } diff -Nru rust-colorsys-0.5.7/src/hsl/ops.rs rust-colorsys-0.6.5/src/hsl/ops.rs --- rust-colorsys-0.5.7/src/hsl/ops.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/src/hsl/ops.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,23 @@ +use core::ops::{Add, AddAssign, Sub, SubAssign}; + +use crate::{ApproxEq, DEFAULT_APPROX_EQ_PRECISION, Rgb}; + +use super::Hsl; + +ops_def!(Hsl); + +impl ApproxEq for Hsl { + fn approx_eq(&self, rgb: &Rgb) -> bool { + self.approx_eq_clarify(rgb, DEFAULT_APPROX_EQ_PRECISION) + } + fn approx_eq_clarify(&self, rgb: &Rgb, precision: f64) -> bool { + let hsl_from_rgb: Hsl = rgb.into(); + self.units.approx_eq_clarify(&hsl_from_rgb.units, precision) + } +} + +#[test] +fn hsl_add() {} + +#[test] +fn hsl_eq() {} diff -Nru rust-colorsys-0.5.7/src/hsl/opts.rs rust-colorsys-0.6.5/src/hsl/opts.rs --- rust-colorsys-0.5.7/src/hsl/opts.rs 2020-08-26 20:25:36.000000000 +0000 +++ rust-colorsys-0.6.5/src/hsl/opts.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,117 +0,0 @@ -use super::Hsl; - -// use crate::common::simple_rand; - -#[allow(unused_imports)] -use crate::{ - common, normalize::normalize_opt_ratio, ColorAlpha, ColorTuple, ColorTupleA, - Rgb, -}; -use common::{approx::*, ops}; - -use std::ops::{Add, AddAssign, Sub, SubAssign}; - -fn add_sub(hsl1: &Hsl, hsl2: &Hsl, is_add: bool) -> Hsl { - type TA = (ColorTuple, Option); - let ta1: TA = (hsl1.into(), hsl1.a); - let ta2: TA = (hsl2.into(), hsl2.a); - let (t, a) = ops::add_sub_tuples_a(&ta1, &ta2, is_add); - let mut hsl = Hsl::from(t); - hsl.a = normalize_opt_ratio(a); - hsl -} - -fn add(hsl1: &Hsl, hsl2: &Hsl) -> Hsl { - add_sub(hsl1, hsl2, true) -} - -fn sub(hsl1: &Hsl, hsl2: &Hsl) -> Hsl { - add_sub(hsl1, hsl2, false) -} - -impl<'a> Add for &'a Hsl { - type Output = Hsl; - fn add(self, rhs: &Hsl) -> Hsl { - add(self, rhs) - } -} - -impl<'a> Add for &'a mut Hsl { - type Output = Hsl; - fn add(self, rhs: &'a mut Hsl) -> Hsl { - add(self, rhs) - } -} - -impl Add for Hsl { - type Output = Hsl; - fn add(self, rhs: Self) -> Self { - add(&self, &rhs) - } -} - -impl AddAssign for Hsl { - fn add_assign(&mut self, rhs: Self) { - *self = add(self, &rhs); - } -} - -impl Sub for Hsl { - type Output = Hsl; - fn sub(self, rhs: Self) -> Self { - sub(&self, &rhs) - } -} - -impl<'a> Sub for &'a Hsl { - type Output = Hsl; - fn sub(self, rhs: Self) -> Hsl { - sub(self, rhs) - } -} - -impl<'a> Sub for &'a mut Hsl { - type Output = Hsl; - fn sub(self, rhs: Self) -> Hsl { - sub(self, rhs) - } -} - -impl SubAssign for Hsl { - fn sub_assign(&mut self, rhs: Self) { - *self = sub(self, &rhs); - } -} - -impl ApproxEq for Hsl { - fn approx_eq(&self, other: &Hsl) -> bool { - let t1: ColorTuple = self.into(); - let t2: ColorTuple = other.into(); - approx_tuple_def(&t1, &t2) - && approx_def(self.get_alpha(), other.get_alpha()) - } - fn approx_eq_clarify(&self, other: &Hsl, precision: f64) -> bool { - let t1: ColorTuple = self.into(); - let t2: ColorTuple = other.into(); - approx_tuple(&t1, &t2, precision) - && approx(self.get_alpha(), other.get_alpha(), precision) - } -} - -impl ApproxEq for Hsl { - fn approx_eq(&self, rgb: &Rgb) -> bool { - self.approx_eq_clarify(rgb, DEFAULT_APPROX_EQ_PRECISION) - } - fn approx_eq_clarify(&self, rgb: &Rgb, precision: f64) -> bool { - let t1: ColorTuple = self.into(); - let t2: ColorTuple = Hsl::from(rgb).into(); - approx_tuple(&t1, &t2, precision) - && approx(self.get_alpha(), rgb.get_alpha(), precision) - } -} - -#[test] -fn hsl_add() {} - -#[test] -fn hsl_eq() {} diff -Nru rust-colorsys-0.5.7/src/hsl/ratio.rs rust-colorsys-0.6.5/src/hsl/ratio.rs --- rust-colorsys-0.5.7/src/hsl/ratio.rs 2020-09-27 19:21:09.000000000 +0000 +++ rust-colorsys-0.6.5/src/hsl/ratio.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,4 +1,4 @@ -use crate::normalize::normalize_ratio; +use crate::units::{Units, GetColorUnits}; /// /// Hsl representation as ratio (from `0.0` to `1.0`). @@ -24,39 +24,36 @@ /// #[derive(Clone)] pub struct HslRatio { - pub(super) h: f64, - pub(super) s: f64, - pub(super) l: f64, - pub(super) a: f64, + pub(super) units: Units, } impl HslRatio { pub fn new(h: f64, s: f64, l: f64, a: f64) -> Self { - HslRatio { - h: normalize_ratio(h), - s: normalize_ratio(s), - l: normalize_ratio(l), - a: normalize_ratio(a), - } + let mut units = Units::new_ratios(&[h, s, l]); + units.alpha.set(a); + HslRatio::from_units(units) } - pub fn h(&self) -> f64 { - self.h - } - pub fn s(&self) -> f64 { - self.s - } - pub fn l(&self) -> f64 { - self.l - } - pub fn a(&self) -> f64 { - self.a - } + pub fn h(&self) -> f64 { self.units[0] } + pub fn s(&self) -> f64 { self.units[1] } + pub fn l(&self) -> f64 { self.units[2] } + pub fn a(&self) -> f64 { self.units.alpha.get_f64() } + + pub(crate) fn from_units(u: Units) -> Self { HslRatio { units: u } } } impl AsRef for HslRatio { fn as_ref(&self) -> &HslRatio { - &self + self + } +} + +impl GetColorUnits for HslRatio { + fn get_units(&self) -> &Units { + &self.units + } + fn get_units_mut(&mut self) -> &mut Units { + &mut self.units } } @@ -102,20 +99,20 @@ macro_rules! into_for_hsl_ratio_all { ($t: ty) => { into_for_some!(($t, $t, $t), HslRatio, self, { - let HslRatio { h, s, l, .. } = *self; - (h as $t, s as $t, l as $t) + let u = &self.get_units(); + (u[0] as $t, u[1] as $t, u[2] as $t) }); into_for_some!(($t, $t, $t, $t), HslRatio, self, { - let HslRatio { h, s, l, a } = *self; - (h as $t, s as $t, l as $t, a as $t) + let u = &self.get_units(); + (u[0] as $t, u[1] as $t, u[2] as $t, u.alpha.get_f64() as $t) }); into_for_some!([$t; 3], HslRatio, self, { - let HslRatio { h, s, l, .. } = *self; - [h as $t, s as $t, l as $t] + let u = &self.get_units(); + [u[0] as $t, u[1] as $t, u[2] as $t] }); into_for_some!([$t; 4], HslRatio, self, { - let HslRatio { h, s, l, a } = *self; - [h as $t, s as $t, l as $t, a as $t] + let u = &self.get_units(); + [u[0] as $t, u[1] as $t, u[2] as $t, u.alpha.get_f64() as $t] }); }; } diff -Nru rust-colorsys-0.5.7/src/hsl/tests.rs rust-colorsys-0.6.5/src/hsl/tests.rs --- rust-colorsys-0.5.7/src/hsl/tests.rs 2020-09-27 19:18:47.000000000 +0000 +++ rust-colorsys-0.6.5/src/hsl/tests.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,7 +1,8 @@ use crate::{ApproxEq, ColorTuple, Hsl, Rgb}; +use crate::common::f64_round; fn round(n: f64) -> u32 { - n.round() as u32 + f64_round( n ) as u32 } fn round_tuple(t: &ColorTuple) -> (u32, u32, u32) { let (x, y, z) = *t; @@ -12,7 +13,12 @@ fn hsl_to_rgb() { let hsl = Hsl::from((126.0, 43.0, 52.0)); let rgb = Rgb::from(&hsl); + #[cfg(feature = "std")] assert_eq!(round_tuple(&rgb.as_ref().into()), (80, 185, 90)); + + #[cfg(not(feature = "std"))] + assert_eq!(round_tuple(&rgb.as_ref().into()), (79, 185, 90)); + let hsl_new = Hsl::from(&rgb); assert!(hsl_new.approx_eq(&hsl)); // let x: ColorTuple = hsl.into(); diff -Nru rust-colorsys-0.5.7/src/hsl/transform.rs rust-colorsys-0.6.5/src/hsl/transform.rs --- rust-colorsys-0.5.7/src/hsl/transform.rs 2020-08-26 20:25:36.000000000 +0000 +++ rust-colorsys-0.6.5/src/hsl/transform.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,33 +1,34 @@ +use crate::{ColorTransform, SaturationInSpace}; use crate::consts::{ALL_MIN, HUE_MAX}; use crate::normalize::bound_hue; -use crate::{ColorTransform, SaturationInSpace}; use super::Hsl; impl ColorTransform for Hsl { fn lighten(&mut self, amt: f64) { - self.set_lightness(self.l + amt) + self.units.list[2].increase(amt); } fn saturate(&mut self, sat: SaturationInSpace) { match sat { - SaturationInSpace::Hsl(s) => self.set_saturation(self.s + s), + SaturationInSpace::Hsl(s) => self.units.list[1].increase(s), SaturationInSpace::Hsv(s) => { - println!("{}", s); - unimplemented!(); + unimplemented!("{}", s); } } } fn adjust_hue(&mut self, hue: f64) { - self.h = bound_hue(self.h + hue); + let h = bound_hue(self.units[0] + hue); + self.units.list[0].set(h); } fn grayscale_simple(&mut self) { - self.h = ALL_MIN; - self.s = ALL_MIN; + self.units.list[0].value = ALL_MIN; + self.units.list[1].value = ALL_MIN; } fn invert(&mut self) { - self.h = (self.h + HUE_MAX * 0.5) % HUE_MAX + let h = (self.units[0] + HUE_MAX * 0.5) % HUE_MAX; + self.units.list[0].set(h); } } diff -Nru rust-colorsys-0.5.7/src/lib.rs rust-colorsys-0.6.5/src/lib.rs --- rust-colorsys-0.5.7/src/lib.rs 2020-09-27 19:48:45.000000000 +0000 +++ rust-colorsys-0.6.5/src/lib.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,7 +1,167 @@ -//! A module for color conversion, mutation, modification. +//! A module for color conversion and mutation written in Rust. //! For now works with RGB(a)( as hexadecimal too), HSL(a) color models +//! +//! ## What It Can Do +//! +//! #### getters & setters +//! ``` +//! use colorsys::{Rgb, Hsl, ColorAlpha}; +//! +//! let rgb = Rgb::from((57.3, 12.7, 53.0)); +//! let r = rgb.red(); +//! // 57.3 +//! +//! let mut hsl = Hsl::default(); +//! // Hsl { h: 0, s: 0, l: 0, a: 1 } +//! hsl.set_saturation(13.98); +//! hsl.set_saturation(305.71); +//! hsl.set_alpha(0.75); +//! // Hsl { h: 305.71, s: 13.98, l: 0, a: 0.75 } +//! ``` +//! +//! #### conversion +//! See `From/FromStr/Into` traits implementation in docs for more info +//! ``` +//! use colorsys::{Rgb, Hsl}; +//! +//! let rbga_tuple = (57.3, 12.7, 53.0, 0.33); +//! let rgba = Rgb::from(&rbga_tuple); +//! let hsla: Hsl = rgba.as_ref().into(); +//! // ~Hsl { h: 305.78, s: 63.71, l: 13.73, a: 0.33 } +//! +//! let rgb_arr: [u8; 3] = Rgb::from(&hsla).into(); +//! // ~[57, 13, 53] +//! +//! let hsla_tuple: (f64,f64,f64,f64) = Hsl::from( Rgb::from(rgb_arr) ).into(); +//! // ~Hsl { h: 305.78, s: 63.71, l: 13.73, a: 1 } +//! +//! let hex: String = rgba.to_hex_string(); +//! // #390d35 +//! +//! +//! // From/Into +//! +//! let rgb1 = Rgb::from_hex_str("37ea4c").unwrap(); +//! +//! let rgb2 = Rgb::from( +//! Into::<[f32; 4]>::into(Rgb::from( +//! Into::<[u16; 3]>::into( +//! Rgb::from( +//! Into::<(i32,i32,i32)>::into( +//! Rgb::from( +//! Into::<[i64; 3]>::into(&rgb1) +//! ) +//! ) +//! ) +//! ) +//! )) +//! ); +//! +//! assert_eq!(rgb1, rgb2); +//! // +//! // Ratio +//! // +//! use colorsys::{RgbRatio, ApproxEq}; +//! let blue = Rgb::from([34, 111, 235]); +//! +//! let ratio: [f32; 4] = blue.as_ratio().into(); +//! // ~[0.133, 0.435, 0.922, 1.0] +//! +//! let converted: Rgb = RgbRatio::from(&ratio).into(); +//! assert!(blue.approx_eq_clarify(&converted, 0.0001)); +//! ``` +//! +//! +//! #### modification +//! See `ColorTransform/Add*/Sub*..` traits in docs for more +//! ``` +//! use colorsys::{Hsl, Rgb, ColorTransform,ColorAlpha, SaturationInSpace}; +//! +//! let mut rgb: Rgb = (245.0,152.0,53.0).into(); +//! +//! rgb.lighten(20.1); +//! // ~Rgb { r: 249.83, g: 201.80, b: 150.67 } +//! +//! rgb.opacify(-0.7); +//! rgb.saturate( SaturationInSpace::Hsl(-35.7) ); +//! // ~Rgb { r: 230.29, g: 201.19, b: 170.21, a: 0.3 } +//! +//! rgb.grayscale_simple(); +//! // ~Rgb { r: 200.255, g: 200.255, b: 200.255, a: 0.3 } +//! +//! +//! let mut hsl = Hsl::from(&rgb); +//! hsl.opacify(1.0); +//! // ~Hsl { h: 0.0, s: 0.0, l: 78.53 } +//! +//! hsl.adjust_hue(231.99); +//! hsl.saturate(SaturationInSpace::Hsl(55.7)); +//! +//! let mut rgb2: Rgb = hsl.as_ref().into(); +//! // ~Rgb { r: 169.76, g: 177.9, b: 230.75} +//! +//! rgb2.invert(); +//! // ~Rgb { r: 85.24, g: 77.09, b: 24.25 } +//! +//! let rgb3 = rgb - rgb2; +//! // ~Rgb { r: 115.01, g: 123.16, b: 176.0 } +//! +//! let hsl2 = hsl + rgb3.into(); +//! // ~Hsl { h: 0.0, s: 83.55, l: 100.0 } +//! +//! ``` +//! +//! #### parsing from string & css string representation +//! ``` +//! use colorsys::{Hsl, Rgb}; +//! use std::str::FromStr; +//! +//! let s = "rgb(177, 255, 176)"; +//! +//! let rgb: Rgb = s.parse().unwrap(); +//! +//! rgb.to_css_string(); +//! // String: "rgb(177,255,176)" +//! +//! rgb.to_hex_string(); +//! // #b1ffb0 +//! +//! Hsl::from_str("hsl(168, 52%, 42%)").unwrap().to_css_string(); +//! // String: hsl(168,52%,42%) +//! +//! ``` +//! +//! ## `no_std` +//! Crate has a Cargo feature named `"std"` that is enabled by default. +//! In order to use `colorsys` in a `no_std` context this feature needs to be disabled. +//! Modify your dependency to opt out of enabled-by-default features. +//! ```toml +//! [dependencies] +//! colorsys = { version = "*", default-features = false } +//! ``` +//! +//! ## Color unit ranges +//! All color units is f64. Here are their ranges: +//! - red - 0.0 .. 255.0 +//! - green - 0.0 .. 255.0 +//! - blue - 0.0 .. 255.0 +//! - hue - 0.0 .. 360.0 +//! - saturation - 0.0 .. 100.0 +//! - lightness - 0.0 .. 100.0 +//! - alpha - 0.0 .. 1.0 +//! +//! If you specify a value that does not fit within these ranges, they are replaced with a minimum or maximum value. +//! +//! #![allow(clippy::many_single_char_names)] +#![allow(clippy::from_over_into)] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +#[macro_use] +extern crate alloc; + mod macros; mod common; @@ -11,15 +171,22 @@ mod hsl; mod normalize; mod rgb; +mod ansi; +mod cmyk; +mod units; pub mod prelude; pub mod ratio_converters; + pub use common::approx::{ApproxEq, DEFAULT_APPROX_EQ_PRECISION}; +pub use common::{ColorUnitsIter, ColorAlpha}; pub use err::ParseError; pub use hsl::{Hsl, HslRatio}; pub use rgb::{GrayScaleMethod, Rgb, RgbRatio}; +pub use cmyk::{Cmyk,CmykRatio}; +pub use ansi::{Ansi256}; -/// Use to transfer nad collect color values. +/// Use to transfer and collect color values. /// May be for example `($red,$green,$blue)` or `($hue,$saturation,$value)` pub type ColorTuple = (f64, f64, f64); @@ -31,31 +198,6 @@ Hsv(f64), } -/// Methods to work with alpha channel in color. -pub trait ColorAlpha { - /// Returns alpha channel. If it not set will returns 1.0 - fn get_alpha(&self) -> f64; - - /// Sets alpha channel - /// ``` - /// use colorsys::{Hsl,ColorAlpha}; - /// let mut hsl = Hsl::default(); // Hsl { a: None, .. } - /// hsl.set_alpha(0.45); // Hsl { a: 0.45, .. } - /// hsl.set_alpha(123.015); // Hsl { a: 1.0, .. } - /// hsl.set_alpha(-123.3); // Hsl { a: 0.0, .. } - /// ``` - fn set_alpha(&mut self, val: f64); - - /// Increase/decrease color alpha channel with specified value. Value can be negative. - /// # Example - /// ``` - /// use colorsys::{Hsl,ColorAlpha}; - /// let mut hsl = Hsl::default(); // Hsl { a: None, .. } - /// hsl.opacify(-0.3); // Hsl { a: 0.7, .. } - /// hsl.opacify(0.015); // Hsl { a: 0.715, .. } - /// ``` - fn opacify(&mut self, val: f64); -} /// A collection of methods to some special modification of color. /// Some methods (like saturate, lighten, etc.) requires (inside implementation) @@ -79,3 +221,4 @@ /// Just inverts color fn invert(&mut self); } + diff -Nru rust-colorsys-0.5.7/src/macros.rs rust-colorsys-0.6.5/src/macros.rs --- rust-colorsys-0.5.7/src/macros.rs 2020-09-24 22:54:05.000000000 +0000 +++ rust-colorsys-0.6.5/src/macros.rs 1973-11-29 21:33:09.000000000 +0000 @@ -21,3 +21,71 @@ } }; } + + + + +macro_rules! ops_def { + ($name: ident) => { + +impl<'a> Add for &'a $name { + type Output = $name; + fn add(self, rhs: &$name) -> $name { $name::from_units(&self.units + &rhs.units) } +} +impl<'a> Add for &'a mut $name { + type Output = $name; + fn add(self, rhs: &'a mut $name) -> $name { $name::from_units(&self.units + &rhs.units) } +} +impl Add for $name { + type Output = $name; + fn add(self, rhs: Self) -> Self { $name::from_units(&self.units + &rhs.units) } +} +impl AddAssign for $name { + fn add_assign(&mut self, rhs: Self) { *self = $name::from_units(&self.units + &rhs.units); } +} + + +impl Sub for $name { + type Output = $name; + fn sub(self, rhs: Self) -> Self { $name::from_units(&self.units - &rhs.units) } +} + +impl<'a> Sub for &'a $name { + type Output = $name; + fn sub(self, rhs: Self) -> $name { $name::from_units(&self.units - &rhs.units) } +} + +impl<'a> Sub for &'a mut $name { + type Output = $name; + fn sub(self, rhs: Self) -> $name { $name::from_units(&self.units - &rhs.units) } +} + +impl SubAssign for $name { + fn sub_assign(&mut self, rhs: Self) { *self = $name::from_units(&self.units - &rhs.units); } +} + +}; +} + + + +macro_rules! iter_def { + ($name: ident) => { +impl<'a> core::iter::IntoIterator for &'a $name { + type Item = f64; + type IntoIter = ColorUnitsIter; + fn into_iter(self) -> ColorUnitsIter { + self.iter() + } +} + +impl core::iter::IntoIterator for $name { + type Item = f64; + type IntoIter = ColorUnitsIter; + fn into_iter(self) -> ColorUnitsIter { + self.iter() + } +} + +}; +} diff -Nru rust-colorsys-0.5.7/src/normalize.rs rust-colorsys-0.6.5/src/normalize.rs --- rust-colorsys-0.5.7/src/normalize.rs 2020-08-26 20:25:36.000000000 +0000 +++ rust-colorsys-0.6.5/src/normalize.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,6 +1,6 @@ -use crate::common::approx::approx_def; use super::consts::{ALL_MIN, HUE_MAX, PERCENT_MAX, RATIO_MAX, RGB_UNIT_MAX}; +use crate::common::{f64_round}; fn normalize(val: f64, max: f64) -> f64 { if val < ALL_MIN { @@ -16,15 +16,6 @@ normalize(val, PERCENT_MAX) } -pub fn normalize_hue(h: f64) -> f64 { - let h = normalize(h, HUE_MAX); - if (h - HUE_MAX).abs() < std::f64::EPSILON { - 0.0 - } else { - h - } -} - pub fn normalize_rgb_unit(val: f64) -> f64 { normalize(val, RGB_UNIT_MAX) } @@ -33,9 +24,6 @@ normalize(val, RATIO_MAX) } -pub fn normalize_opt_ratio(val: Option) -> Option { - val.map(normalize_ratio).filter(|al| !approx_def(*al, RATIO_MAX)) -} pub fn bound(r: f64, entire: f64) -> f64 { let mut n = r; @@ -62,5 +50,5 @@ } pub fn round_ratio(r: f64) -> f64 { - (r * 100.0).round() / 100.0 + f64_round(r * 100.0) / 100.0 } diff -Nru rust-colorsys-0.5.7/src/rgb/from.rs rust-colorsys-0.6.5/src/rgb/from.rs --- rust-colorsys-0.5.7/src/rgb/from.rs 2020-09-27 18:43:15.000000000 +0000 +++ rust-colorsys-0.6.5/src/rgb/from.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,8 +1,8 @@ -use crate::converters::*; -use crate::rgb::RgbRatio; use crate::{ - ratio_converters::ratio_to_rgba, ColorAlpha, ColorTuple, Hsl, Rgb, + ColorAlpha, Hsl, ratio_converters::ratio_to_rgba, Rgb, }; +use crate::converters::*; +use crate::rgb::RgbRatio; macro_rules! from_for_rgb { ($from_type: ty, $val: ident, $conv: block) => { @@ -25,14 +25,19 @@ let (r, g, b) = *v; Rgb::new(r as f64, g as f64, b as f64, None) }); - from_for_rgb!(($t, $t, $t, $t), v, { - let (r, g, b, a) = *v; - Rgb::new(r as f64, g as f64, b as f64, Some(a as f64)) - }); from_for_rgb!([$t; 3], v, { let [r, g, b] = *v; Rgb::new(r as f64, g as f64, b as f64, None) }); + }; +} + +macro_rules! from_for_rgb_all_with_alpha { + ($t: ty) => { + from_for_rgb!(($t, $t, $t, $t), v, { + let (r, g, b, a) = *v; + Rgb::new(r as f64, g as f64, b as f64, Some(a as f64)) + }); from_for_rgb!([$t; 4], v, { let [r, g, b, a] = *v; Rgb::new(r as f64, g as f64, b as f64, Some(a as f64)) @@ -42,6 +47,8 @@ from_for_rgb_all!(f32); from_for_rgb_all!(f64); +from_for_rgb_all_with_alpha!(f32); +from_for_rgb_all_with_alpha!(f64); from_for_rgb_all!(i16); from_for_rgb_all!(i32); from_for_rgb_all!(i64); @@ -51,9 +58,8 @@ from_for_rgb_all!(u64); fn from_hsl(hsl: &Hsl) -> Rgb { - let a = hsl.get_alpha(); - let tuple: ColorTuple = hsl.into(); - let mut rgb = Rgb::from(hsl_to_rgb(&tuple)); + let a = hsl.alpha(); + let mut rgb = Rgb::from_units(hsl_to_rgb(hsl)); rgb.set_alpha(a); rgb } @@ -98,9 +104,11 @@ } fn from_rgb_ratio(ratio: &RgbRatio) -> Rgb { - let t = ratio_to_rgba(&(ratio.r, ratio.g, ratio.b, ratio.a)); - Rgb { r: t.0, g: t.1, b: t.2, a: Some(t.3) } + let ru = &ratio.units; + let t = ratio_to_rgba(&(ru[0], ru[1], ru[2], ru.alpha.get_f64())); + Rgb::new(t.0, t.1, t.2,Some(t.3)) } + impl From<&RgbRatio> for Rgb { fn from(r: &RgbRatio) -> Self { from_rgb_ratio(r) @@ -130,26 +138,33 @@ macro_rules! into_for_rgb_all { ($t: ty) => { into_for_some!(($t, $t, $t), Rgb, self, { - let Rgb { r, g, b, .. } = *self; - (r as $t, g as $t, b as $t) - }); - into_for_some!(($t, $t, $t, $t), Rgb, self, { - let Rgb { r, g, b, .. } = *self; - (r as $t, g as $t, b as $t, self.get_alpha() as $t) + let u = &self.units; + (u[0] as $t, u[1] as $t, u[2] as $t) }); into_for_some!([$t; 3], Rgb, self, { - let Rgb { r, g, b, .. } = *self; - [r as $t, g as $t, b as $t] + let u = &self.units; + [u[0] as $t, u[1] as $t, u[2] as $t] + }); + }; +} + +macro_rules! into_for_rgb_all_with_alpha { + ($t: ty) => { + into_for_some!(($t, $t, $t, $t), Rgb, self, { + let u = &self.units; + (u[0] as $t, u[1] as $t, u[2] as $t, self.units.alpha.get_f64() as $t) }); into_for_some!([$t; 4], Rgb, self, { - let Rgb { r, g, b, .. } = *self; - [r as $t, g as $t, b as $t, self.get_alpha() as $t] + let u = &self.units; + [u[0] as $t, u[1] as $t, u[2] as $t, self.units.alpha.get_f64() as $t] }); }; } into_for_rgb_all!(f32); into_for_rgb_all!(f64); +into_for_rgb_all_with_alpha!(f32); +into_for_rgb_all_with_alpha!(f64); into_for_rgb_all!(i16); into_for_rgb_all!(i32); into_for_rgb_all!(i64); diff -Nru rust-colorsys-0.5.7/src/rgb/from_str.rs rust-colorsys-0.6.5/src/rgb/from_str.rs --- rust-colorsys-0.5.7/src/rgb/from_str.rs 2020-09-27 19:37:50.000000000 +0000 +++ rust-colorsys-0.6.5/src/rgb/from_str.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,8 +1,11 @@ -use crate::err::{make_parse_err, ParseError}; -use crate::{consts, ColorTuple}; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; use consts::{ALL_MIN, RATIO_MAX, RGB_UNIT_MAX}; +use crate::{ColorTuple, consts}; +use crate::err::{make_parse_err, ParseError}; + pub fn rgb(s: &str) -> Result<(ColorTuple, Option), ParseError> { let make_err = || Err(make_parse_err(s, "rgb or rgba")); let s = s.trim().to_lowercase().replace(" ", ""); diff -Nru rust-colorsys-0.5.7/src/rgb/grayscale.rs rust-colorsys-0.6.5/src/rgb/grayscale.rs --- rust-colorsys-0.5.7/src/rgb/grayscale.rs 2020-08-26 20:25:36.000000000 +0000 +++ rust-colorsys-0.6.5/src/rgb/grayscale.rs 1973-11-29 21:33:09.000000000 +0000 @@ -28,9 +28,10 @@ (R_REC2100_FACTOR, G_REC2100_FACTOR, B_REC2100_FACTOR); fn mul(rgb: &mut Rgb, factors: ColorTuple) { - rgb.r *= factors.0; - rgb.g *= factors.1; - rgb.b *= factors.2; + let mut vals = &mut rgb.units.list; + vals[0].value *= factors.0; + vals[1].value *= factors.1; + vals[2].value *= factors.2; } fn rgb_to_grayscale_lum(rgb: &mut Rgb) { @@ -40,25 +41,27 @@ fn rgb_to_grayscale_rec709(rgb: &mut Rgb) { mul(rgb, REC709_FACTORS); } + fn rgb_to_grayscale_rec2100(rgb: &mut Rgb) { mul(rgb, REC2100_FACTORS); } fn rgb_to_grayscale_avg(rgb: &mut Rgb) { - let y = (rgb.r + rgb.g + rgb.b) / 3.0; - rgb.r = y; - rgb.g = y; - rgb.b = y; + let mut vals = &mut rgb.units.list; + let y = (vals[0].value + vals[1].value + vals[2].value) / 3.0; + vals[0].value = y; + vals[1].value = y; + vals[2].value = y; } fn rgb_to_grayscale_avg_prom(rgb: &mut Rgb) { - let rgb_vec = vec![rgb.r, rgb.g, rgb.b]; - let max = rgb_vec.iter().fold(std::f64::MIN, |a, &b| a.max(b)); - let min = rgb_vec.iter().fold(std::f64::MAX, |a, &b| a.min(b)); - let y = (max + min) / 2.0; - rgb.r = y; - rgb.g = y; - rgb.b = y; + let max = rgb.units.max(); + let min = rgb.units.min(); + let y = (max.0 + min.0) / 2.0; + let mut vals = &mut rgb.units.list; + vals[0].value = y; + vals[1].value = y; + vals[2].value = y; } pub fn rgb_grayscale(rgb: &mut Rgb, method: GrayScaleMethod) { diff -Nru rust-colorsys-0.5.7/src/rgb/mod.rs rust-colorsys-0.6.5/src/rgb/mod.rs --- rust-colorsys-0.5.7/src/rgb/mod.rs 2020-09-24 22:40:29.000000000 +0000 +++ rust-colorsys-0.6.5/src/rgb/mod.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,11 +1,17 @@ -#[cfg(test)] -mod tests; +#[cfg(not(feature = "std"))] +use alloc::string::String; -use crate::common::{approx::approx_def, tuple_to_string, ColorIter}; -use crate::consts::RATIO_MAX; +pub use grayscale::GrayScaleMethod; +use grayscale::rgb_grayscale; +pub use ratio::RgbRatio; + +use crate::{ColorAlpha, ColorTuple, ColorTupleA, converters, Hsl, ColorUnitsIter}; +use crate::common::{tuple_to_string}; use crate::err::ParseError; -use crate::normalize::{normalize_ratio, normalize_rgb_unit}; -use crate::{converters, ColorAlpha, ColorTuple, ColorTupleA, Hsl}; +use crate::units::{Alpha, GetColorUnits, Unit, Units}; + +#[cfg(test)] +mod tests; mod from; mod from_str; @@ -14,28 +20,20 @@ mod ratio; mod transform; -use crate::ratio_converters::rgba_to_ratio; -use grayscale::rgb_grayscale; -pub use grayscale::GrayScaleMethod; -pub use ratio::RgbRatio; - /// The RGB color model. /// -/// Has r (red), g (green), b(blue) and optional a(alpha channel) fields. +/// Has red, green, blue and optional `alpha` channel fields. /// Red, green, blue values are stored between 0.0 and 255.0, alpha is between 0.0 and 1.0. -/// If inputed or recieved values are exceeds the allowed value, or is less than zero +/// If inputted or received values are exceeds the allowed value, or is less than zero /// it will be equalize to limit. /// -/// Can be converted into (and from) other color models. -/// -/// /// # Example /// ``` /// use colorsys::{Rgb, Hsl, prelude::*}; /// let mut rgb1 = Rgb::from((100.0, 255.0, 17.0)); /// // Rgb { r: 100.0, g: 255.0, b: 17.0, a: None } /// -/// let green = rgb1.get_green(); +/// let green = rgb1.green(); /// // 255.0 /// /// rgb1.set_red(108.3); @@ -57,7 +55,7 @@ /// // ~Rgb { r: 177.33, g: 255.0, b: 176.902, .. } /// /// rgb2.set_green(-150.0); -/// assert_eq!(rgb2.get_green(), 0.0); +/// assert_eq!(rgb2.green(), 0.0); /// /// rgb2.lighten(-13.123); /// // ~Rgb { r: 110.41, g: 0.0, b: 110.1, .. } @@ -71,24 +69,30 @@ /// #[derive(Debug, PartialEq, Clone)] pub struct Rgb { - r: f64, - g: f64, - b: f64, - a: Option, + pub(crate) units: Units, +} + +iter_def!(Rgb); + +pub(crate) fn new_rgb_units(r: f64, g: f64, b: f64) -> Units { + let ul = [Unit::new_rgb(r), Unit::new_rgb(g), Unit::new_rgb(b), Unit::default()]; + Units { len: 3, list: ul, alpha: Alpha::default() } } impl Rgb { fn _apply_tuple(&mut self, t: &ColorTuple) { - self.r = t.0; - self.g = t.1; - self.b = t.2; + self.units.list[0].value = t.0; + self.units.list[1].value = t.1; + self.units.list[2].value = t.2; } - pub fn new(r: f64, g: f64, b: f64, a: Option) -> Rgb { - let n = normalize_rgb_unit; + pub(crate) fn from_units(u: Units) -> Self { Rgb { units: u } } - let a = a.map(normalize_ratio).filter(|al| !approx_def(*al, RATIO_MAX)); - Rgb { r: n(r), g: n(g), b: n(b), a } + pub fn new(r: f64, g: f64, b: f64, a: Option) -> Rgb { + let mut units = new_rgb_units(r, g, b); + units.alpha.set_opt(a); + units.restrict(); + Rgb { units } } pub fn from_hex_str(s: &str) -> Result { @@ -100,26 +104,37 @@ converters::rgb_to_hex(&self.into()) } - pub fn get_red(&self) -> f64 { - self.r + pub fn red(&self) -> f64 { self.units[0] } + pub fn green(&self) -> f64 { + self.units[1] } - pub fn get_green(&self) -> f64 { - self.g - } - pub fn get_blue(&self) -> f64 { - self.b + pub fn blue(&self) -> f64 { + self.units[2] } - pub fn set_red(&mut self, val: f64) { - self.r = normalize_rgb_unit(val); - } - pub fn set_green(&mut self, val: f64) { - self.g = normalize_rgb_unit(val); + #[deprecated(since = "0.7.0", note = "Please use `red` instead")] + pub fn get_red(&self) -> f64 { self.red() } + #[deprecated(since = "0.7.0", note = "Please use `green` instead")] + pub fn get_green(&self) -> f64 { + self.green() } - pub fn set_blue(&mut self, val: f64) { - self.b = normalize_rgb_unit(val); + #[deprecated(since = "0.7.0", note = "Please use `blue` instead")] + pub fn get_blue(&self) -> f64 { + self.blue() } + pub fn set_red(&mut self, val: f64) { self.units.list[0].set(val); } + pub fn set_green(&mut self, val: f64) { self.units.list[1].set(val); } + pub fn set_blue(&mut self, val: f64) { self.units.list[2].set(val); } + + /// Returns a String that can be used in CSS. + /// # Example + /// ``` + /// use colorsys::{Rgb}; + /// + /// let rgb = Rgb::from([55.0,31.1, 201.9]); + /// assert_eq!(rgb.to_css_string(), "rgb(55,31,202)"); + /// ``` pub fn to_css_string(&self) -> String { let t: ColorTupleA = self.into(); tuple_to_string(&t, "rgb") @@ -129,13 +144,14 @@ rgb_grayscale(self, method); } - pub fn iter(&self) -> ColorIter { - ColorIter::from_tuple_w_alpha(self.into(), self.a) + /// Returns an iterator over three color units and the possibly alpha value. + pub fn iter(&self) -> ColorUnitsIter { + ColorUnitsIter::from_units(&self.units) } + /// Returns an RGB representation with values converted to floar from 0.0 to 1.0 pub fn as_ratio(&self) -> RgbRatio { - let t = rgba_to_ratio(&self.into()); - RgbRatio { r: t.0, g: t.1, b: t.2, a: t.3 } + RgbRatio::from_units(self.units.as_ratio()) } } @@ -146,7 +162,7 @@ // impl Default for Rgb { fn default() -> Rgb { - Rgb { r: 0.0, g: 0.0, b: 0.0, a: None } + Rgb::from_units(new_rgb_units(0.0, 0.0, 0.0)) } } @@ -157,7 +173,16 @@ // impl AsRef for Rgb { fn as_ref(&self) -> &Rgb { - &self + self + } +} + +impl GetColorUnits for Rgb { + fn get_units(&self) -> &Units { + &self.units + } + fn get_units_mut(&mut self) -> &mut Units { + &mut self.units } } @@ -166,7 +191,7 @@ // // FromStr // -impl std::str::FromStr for Rgb { +impl core::str::FromStr for Rgb { type Err = ParseError; fn from_str(s: &str) -> Result { let (tuple, alpha) = from_str::rgb(s)?; @@ -177,43 +202,3 @@ Ok(rgb) } } - -// -// -// -// ColorAlpha -// -impl ColorAlpha for Rgb { - fn get_alpha(&self) -> f64 { - self.a.unwrap_or(1.0) - } - - fn set_alpha(&mut self, val: f64) { - self.a = Some(normalize_ratio(val)); - } - - fn opacify(&mut self, val: f64) { - self.set_alpha(self.get_alpha() + val); - } -} - -// -// -// -// Iter -// -impl<'a> std::iter::IntoIterator for &'a Rgb { - type Item = f64; - type IntoIter = ColorIter; - fn into_iter(self) -> ColorIter { - self.iter() - } -} - -impl std::iter::IntoIterator for Rgb { - type Item = f64; - type IntoIter = ColorIter; - fn into_iter(self) -> ColorIter { - self.iter() - } -} diff -Nru rust-colorsys-0.5.7/src/rgb/ops.rs rust-colorsys-0.6.5/src/rgb/ops.rs --- rust-colorsys-0.5.7/src/rgb/ops.rs 2020-08-26 20:25:36.000000000 +0000 +++ rust-colorsys-0.6.5/src/rgb/ops.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,143 +1,49 @@ -use super::Rgb; +use core::ops::{Add, AddAssign, Sub, SubAssign}; -// use crate::common::simple_rand; +use crate::{ApproxEq, DEFAULT_APPROX_EQ_PRECISION, Hsl, Rgb}; -#[allow(unused_imports)] -use crate::{ - common, normalize::normalize_opt_ratio, ColorAlpha, ColorTuple, ColorTupleA, - Hsl, -}; -use common::{approx::*, ops}; - -use std::ops::{Add, AddAssign, Sub, SubAssign}; - -fn add_sub(rgb1: &Rgb, rgb2: &Rgb, is_add: bool) -> Rgb { - type TA = (ColorTuple, Option); - let ta1: TA = (rgb1.into(), rgb1.a); - let ta2: TA = (rgb2.into(), rgb2.a); - let (t, a) = ops::add_sub_tuples_a(&ta1, &ta2, is_add); - let mut rgb = Rgb::from(t); - rgb.a = normalize_opt_ratio(a); - rgb -} - -fn add(rgb1: &Rgb, rgb2: &Rgb) -> Rgb { - add_sub(rgb1, rgb2, true) -} - -fn sub(rgb1: &Rgb, rgb2: &Rgb) -> Rgb { - add_sub(rgb1, rgb2, false) -} - -impl<'a> Add for &'a Rgb { - type Output = Rgb; - fn add(self, rhs: &Rgb) -> Rgb { - add(self, rhs) - } -} - -impl<'a> Add for &'a mut Rgb { - type Output = Rgb; - fn add(self, rhs: &'a mut Rgb) -> Rgb { - add(self, rhs) - } -} - -impl Add for Rgb { - type Output = Rgb; - fn add(self, rhs: Self) -> Self { - add(&self, &rhs) - } -} - -impl AddAssign for Rgb { - fn add_assign(&mut self, rhs: Self) { - *self = add(self, &rhs); - } -} - -impl Sub for Rgb { - type Output = Rgb; - fn sub(self, rhs: Self) -> Self { - sub(&self, &rhs) - } -} - -impl<'a> Sub for &'a Rgb { - type Output = Rgb; - fn sub(self, rhs: Self) -> Rgb { - sub(self, rhs) - } -} - -impl<'a> Sub for &'a mut Rgb { - type Output = Rgb; - fn sub(self, rhs: Self) -> Rgb { - sub(self, rhs) - } -} - -impl SubAssign for Rgb { - fn sub_assign(&mut self, rhs: Self) { - *self = sub(self, &rhs); - } -} - -impl ApproxEq for Rgb { - fn approx_eq(&self, other: &Rgb) -> bool { - let t1: ColorTuple = self.into(); - let t2: ColorTuple = other.into(); - approx_tuple_def(&t1, &t2) - && approx_def(self.get_alpha(), other.get_alpha()) - } - fn approx_eq_clarify(&self, other: &Rgb, precision: f64) -> bool { - let t1: ColorTuple = self.into(); - let t2: ColorTuple = other.into(); - approx_tuple(&t1, &t2, precision) - && approx(self.get_alpha(), other.get_alpha(), precision) - } -} +ops_def!(Rgb); impl ApproxEq for Rgb { fn approx_eq(&self, hsl: &Hsl) -> bool { self.approx_eq_clarify(hsl, DEFAULT_APPROX_EQ_PRECISION) } + fn approx_eq_clarify(&self, hsl: &Hsl, precision: f64) -> bool { - let t1: ColorTuple = self.into(); - let t2: ColorTuple = Rgb::from(hsl).into(); - approx_tuple(&t1, &t2, precision) - && approx(self.get_alpha(), hsl.get_alpha(), precision) + let rgb: Rgb = hsl.into(); + self.units.approx_eq_clarify(&rgb.units, precision) } } -#[test] -fn rgb_add() { - let rgb1 = Rgb::default(); - let rgb2 = Rgb::from_hex_str("ffcc00").unwrap(); - let rgb3: ColorTupleA = (rgb1 + rgb2).into(); - assert_eq!(Into::::into(rgb3), (255.0, 204.0, 0.0, 1.0)); - - let rgb1 = Rgb::new(200.0, 200.0, 200.0, Some(0.3)); - let rgb2 = Rgb::new(200.0, 200.0, 200.0, None); - let rgb3: ColorTupleA = (rgb1 + rgb2).into(); - assert_eq!(rgb3, (255.0, 255.0, 255.0, 0.3)); -} - -#[test] -fn rgb_eq() { - let rgb1 = Rgb::default(); - let mut rgb2 = Rgb::default(); - let rgb3 = Rgb::from((12.12534, 123.21321, 12.002_310_123)); - let hsl: Hsl = rgb3.as_ref().into(); - let rgb4 = Rgb::from(&hsl); - rgb2 += rgb3.clone(); - rgb2 -= rgb3.clone(); - - assert_eq!(rgb1, rgb2); - assert!(rgb3.approx_eq(&rgb4)); - assert!(rgb3.approx_eq_clarify(&hsl, 0.000_000_000_001)); - - // println!("time {:?}", simple_rand(255.0)); - // println!("time {:?}", simple_rand(255.0)); - // println!("time {:?}", simple_rand(255.0)); +#[cfg(test)] +mod test { + use crate::{ApproxEq, ColorTupleA, Hsl, Rgb}; + + #[test] + fn rgb_add() { + let rgb1 = Rgb::default(); + let rgb2 = Rgb::from_hex_str("ffcc00").unwrap(); + let rgb3: ColorTupleA = (rgb1 + rgb2).into(); + assert_eq!(Into::::into(rgb3), (255.0, 204.0, 0.0, 1.0)); + + let rgb1 = Rgb::new(200.0, 200.0, 200.0, Some(0.3)); + let rgb2 = Rgb::new(200.0, 200.0, 200.0, None); + let rgb3: ColorTupleA = (rgb1 + rgb2).into(); + assert_eq!(rgb3, (255.0, 255.0, 255.0, 0.3)); + } + + #[test] + fn rgb_eq() { + let rgb1 = Rgb::default(); + let mut rgb2 = Rgb::default(); + let rgb3 = Rgb::from((12.12534, 123.21321, 12.002_310_123)); + let hsl: Hsl = rgb3.as_ref().into(); + let rgb4 = Rgb::from(&hsl); + rgb2 += rgb3.clone(); + rgb2 -= rgb3.clone(); + + assert_eq!(rgb1, rgb2); + assert!(rgb3.approx_eq(&rgb4)); + assert!(rgb3.approx_eq_clarify(&hsl, 0.000_000_000_001)); + } } diff -Nru rust-colorsys-0.5.7/src/rgb/ratio.rs rust-colorsys-0.6.5/src/rgb/ratio.rs --- rust-colorsys-0.5.7/src/rgb/ratio.rs 2020-09-27 19:23:37.000000000 +0000 +++ rust-colorsys-0.6.5/src/rgb/ratio.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,4 +1,4 @@ -use crate::normalize::normalize_ratio; +use crate::units::{GetColorUnits, Units}; /// /// Rgb representation as ratio (from `0.0` to `1.0`). @@ -23,41 +23,37 @@ /// /// ``` /// -#[derive(Clone)] +#[derive(Debug, PartialEq, Clone)] pub struct RgbRatio { - pub(super) r: f64, - pub(super) g: f64, - pub(super) b: f64, - pub(super) a: f64, + pub(crate) units: Units, } impl RgbRatio { pub fn new(r: f64, g: f64, b: f64, a: f64) -> Self { - RgbRatio { - r: normalize_ratio(r), - g: normalize_ratio(g), - b: normalize_ratio(b), - a: normalize_ratio(a), - } + let mut units = Units::new_ratios(&[r, g, b]); + units.alpha.set(a); + RgbRatio { units } } - pub fn r(&self) -> f64 { - self.r - } - pub fn g(&self) -> f64 { - self.g - } - pub fn b(&self) -> f64 { - self.b - } - pub fn a(&self) -> f64 { - self.a - } + pub fn r(&self) -> f64 { self.units[0] } + pub fn g(&self) -> f64 { self.units[1] } + pub fn b(&self) -> f64 { self.units[2] } + pub fn a(&self) -> f64 { self.units.alpha.get_f64() } + + pub(crate) fn from_units(u: Units) -> Self { RgbRatio { units: u } } } impl AsRef for RgbRatio { - fn as_ref(&self) -> &RgbRatio { - &self + fn as_ref(&self) -> &RgbRatio { self } +} + + +impl GetColorUnits for RgbRatio { + fn get_units(&self) -> &Units { + &self.units + } + fn get_units_mut(&mut self) -> &mut Units { + &mut self.units } } @@ -103,20 +99,20 @@ macro_rules! into_for_rgb_ratio_all { ($t: ty) => { into_for_some!(($t, $t, $t), RgbRatio, self, { - let RgbRatio { r, g, b, .. } = *self; - (r as $t, g as $t, b as $t) + let u = &self.get_units(); + (u[0] as $t, u[1] as $t, u[2] as $t) }); into_for_some!(($t, $t, $t, $t), RgbRatio, self, { - let RgbRatio { r, g, b, a } = *self; - (r as $t, g as $t, b as $t, a as $t) + let u = &self.get_units(); + (u[0] as $t, u[1] as $t, u[2] as $t, u.alpha.get_f64() as $t) }); into_for_some!([$t; 3], RgbRatio, self, { - let RgbRatio { r, g, b, .. } = *self; - [r as $t, g as $t, b as $t] + let u = &self.get_units(); + [u[0] as $t, u[1] as $t, u[2] as $t] }); into_for_some!([$t; 4], RgbRatio, self, { - let RgbRatio { r, g, b, a } = *self; - [r as $t, g as $t, b as $t, a as $t] + let u = &self.get_units(); + [u[0] as $t, u[1] as $t, u[2] as $t, u.alpha.get_f64() as $t] }); }; } diff -Nru rust-colorsys-0.5.7/src/rgb/tests.rs rust-colorsys-0.6.5/src/rgb/tests.rs --- rust-colorsys-0.5.7/src/rgb/tests.rs 2020-09-27 19:42:10.000000000 +0000 +++ rust-colorsys-0.6.5/src/rgb/tests.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,9 +1,8 @@ -use crate::{ - ApproxEq, ColorTransform, ColorTuple, ColorTupleA, ParseError, Rgb, RgbRatio, -}; +use crate::{ColorTransform, ColorTuple, ColorTupleA, ParseError, Rgb}; +use crate::common::f64_round; fn round(n: f64) -> u32 { - n.round() as u32 + f64_round(n) as u32 } fn round_tuple(t: &ColorTuple) -> (u32, u32, u32) { @@ -19,12 +18,21 @@ let mut rgb4 = rgb.clone(); rgb.lighten(15.0); + + #[cfg(feature = "std")] assert_eq!(round_tuple(&rgb.into()), (135, 208, 142)); + #[cfg(not(feature = "std"))] + assert_eq!(round_tuple(&rgb.into()), (134, 207, 141)); rgb2.lighten(45.0); + #[cfg(feature = "std")] assert_eq!(round_tuple(&rgb2.into()), (245, 251, 245)); + #[cfg(not(feature = "std"))] + assert_eq!(round_tuple(&rgb2.into()), (244, 250, 245)); + rgb3.lighten(-23.0); + #[cfg(feature = "std")] assert_eq!(round_tuple(&rgb3.into()), (42, 107, 48)); rgb4.lighten(-203.0); @@ -62,22 +70,22 @@ fn rgb_iter() { let rgb1 = Rgb::from_hex_str("37ea4c").unwrap(); let rgb2 = Rgb::from_hex_str("ffcc00").unwrap(); - let t: ColorTuple = rgb1.as_ref().into(); - let rgb3 = &rgb1 + &rgb2; - println!(">>> {:?}", rgb3); - println!(">>> {:?}", t); + let _t: ColorTuple = rgb1.as_ref().into(); + let _rgb3 = &rgb1 + &rgb2; + // println!(">>> {:?}", rgb3); + // println!(">>> {:?}", t); } #[test] #[rustfmt::skip] fn rgb_from() { let rgb1 = Rgb::from_hex_str("37ea4c").unwrap(); - + let rgb2 = Rgb::from( Into::<[f32; 4]>::into(Rgb::from( - Into::<[u8; 4]>::into( + Into::<[u8; 3]>::into( Rgb::from( - Into::<(i32,i32,i32)>::into( + Into::<(i32, i32, i32)>::into( Rgb::from( Into::<[i64; 3]>::into(&rgb1) ) diff -Nru rust-colorsys-0.5.7/src/rgb/transform.rs rust-colorsys-0.6.5/src/rgb/transform.rs --- rust-colorsys-0.5.7/src/rgb/transform.rs 2020-08-26 20:25:36.000000000 +0000 +++ rust-colorsys-0.6.5/src/rgb/transform.rs 1973-11-29 21:33:09.000000000 +0000 @@ -1,7 +1,9 @@ -use super::{grayscale, Hsl, Rgb}; -use crate::{consts, ColorTransform, SaturationInSpace}; use consts::RGB_UNIT_MAX; +use crate::{ColorTransform, consts, SaturationInSpace}; + +use super::{grayscale, Hsl, Rgb}; + impl ColorTransform for Rgb { /// Lighten or darken color. amt is a percent with negative values - `-100..100` /// # Example @@ -33,13 +35,12 @@ match sat { SaturationInSpace::Hsl(amt) => { let mut hsl: Hsl = self.into(); - hsl.set_saturation(hsl.get_saturation() + amt); + hsl.set_saturation(hsl.saturation() + amt); let new_rgb = Rgb::from(hsl); self._apply_tuple(&new_rgb.into()); } SaturationInSpace::Hsv(amt) => { - println!("{}", amt); - unimplemented!(); + unimplemented!("{}", amt); } } } @@ -58,33 +59,45 @@ } fn invert(&mut self) { - self.r = RGB_UNIT_MAX - self.r; - self.g = RGB_UNIT_MAX - self.g; - self.b = RGB_UNIT_MAX - self.b; + self.units.list[0].value = RGB_UNIT_MAX - self.units[0]; + self.units.list[1].value = RGB_UNIT_MAX - self.units[1]; + self.units.list[2].value = RGB_UNIT_MAX - self.units[2]; } } -#[test] -fn lighten_darken_test() { - use crate::ColorTuple; - pub fn as_rounded_rgb_tuple(t: &ColorTuple) -> (u16, u16, u16) { - let (r, g, b) = *t; - (r.round() as u16, g.round() as u16, b.round() as u16) - } - - let asserts = [ - ((30.0, 108.0, 77.0), 20.0, (52, 188, 134)), - ((30.0, 108.0, 77.0), 90.0, (255, 255, 255)), - ((30.0, 108.0, 77.0), -20.0, (8, 28, 20)), - ((0.0, 0.0, 0.0), 50.0, (128, 128, 128)), - ((0.0, 0.0, 0.0), -50.0, (0, 0, 0)), - ((0.0, 0.0, 0.0), 300.5, (255, 255, 255)), - ]; - - for a in asserts.iter() { - let (origin, amt, result) = *a; - let mut rgb = Rgb::from(&origin); - rgb.lighten(amt); - assert_eq!(as_rounded_rgb_tuple(&rgb.into()), result); +#[cfg(test)] +mod test { + use crate::{Rgb, ColorTransform}; + + #[test] + fn lighten_darken_test() { + use crate::ColorTuple; + use crate::common::f64_round; + + pub fn as_rounded_rgb_tuple(t: &ColorTuple) -> (u16, u16, u16) { + let (r, g, b) = *t; + (f64_round(r) as u16, f64_round(g) as u16, f64_round(b) as u16) + } + + let asserts = [ + #[cfg(feature = "std")] + ((30.0, 108.0, 77.0), 20.0, (52, 188, 134)), + ((30.0, 108.0, 77.0), 90.0, (255, 255, 255)), + #[cfg(feature = "std")] + ((30.0, 108.0, 77.0), -20.0, (8, 28, 20)), + #[cfg(feature = "std")] + ((0.0, 0.0, 0.0), 50.0, (128, 128, 128)), + #[cfg(not(feature = "std"))] + ((0.0, 0.0, 0.0), 50.0, (127, 127, 127)), + ((0.0, 0.0, 0.0), -50.0, (0, 0, 0)), + ((0.0, 0.0, 0.0), 300.5, (255, 255, 255)), + ]; + + for a in asserts.iter() { + let (origin, amt, result) = *a; + let mut rgb = Rgb::from(&origin); + rgb.lighten(amt); + assert_eq!(as_rounded_rgb_tuple(&rgb.into()), result); + } } } diff -Nru rust-colorsys-0.5.7/src/units/alpha.rs rust-colorsys-0.6.5/src/units/alpha.rs --- rust-colorsys-0.5.7/src/units/alpha.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/src/units/alpha.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,66 @@ + +use super::unit::Unit; + +use crate::consts::{RATIO_MAX}; +use crate::{ApproxEq, DEFAULT_APPROX_EQ_PRECISION}; +use crate::common::approx::approx; + +#[derive(Clone, PartialEq, Debug, Default)] +pub(crate) struct Alpha { + value: Option, +} + +impl Alpha { + // pub(crate) fn from_opt(opt: Option) -> Self { + // if let Some(a) = opt { + // if !a.eq(&RATIO_MAX) { + // return Alpha { value: Some(Unit::new_ratio(a)) } + // } + // } + // Alpha::default() + // } + pub(crate) fn set(&mut self, a: f64) { + if let Some(ref mut u) = &mut self.value { + u.set(a); + } else { + self.value = Some(Unit::new_ratio(a)); + } + if self.value.unwrap().value.eq(&RATIO_MAX) { + self.value = None; + } + } + pub(crate) fn set_opt(&mut self, av: Option) { + if let Some(a) = av { + self.set(a); + } else { self.value = None; } + } + + pub(crate) fn get(&self) -> Option { + self.value.map(|u| u.value) + } + pub(crate) fn get_f64(&self) -> f64 { + self.get().unwrap_or(RATIO_MAX) + } + + pub(crate) fn opacify(&mut self, v: f64) { + self.set(self.get_f64() + v); + } +} + + +impl ApproxEq for Alpha { + fn approx_eq(&self, other: &Alpha) -> bool { + self.approx_eq_clarify(other,DEFAULT_APPROX_EQ_PRECISION) + } + + fn approx_eq_clarify(&self, other: &Alpha, precision: f64) -> bool { + if let Some(su) = &self.value { + if let Some(ou) = &other.value { + return approx(su.value, ou.value, precision) + } + } else { + return other.value.is_none() + } + false + } +} diff -Nru rust-colorsys-0.5.7/src/units/into.rs rust-colorsys-0.6.5/src/units/into.rs --- rust-colorsys-0.5.7/src/units/into.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/src/units/into.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,41 @@ +use crate::units::{Units}; + + +impl<'a> Into<[f64;3]> for &'a Units { + fn into(self) -> [f64; 3] { + [self[0],self[1],self[2]] + } +} +impl Into<[f64;3]> for Units { + fn into(self) -> [f64; 3] { + [self[0],self[1],self[2]] + } +} +impl<'a> Into<[f64;4]> for &'a Units { + fn into(self) -> [f64; 4] { + [self[0],self[1],self[2],self[3]] + } +} +impl Into<[f64;4]> for Units { + fn into(self) -> [f64; 4] { + [self[0],self[1],self[2],self[3]] + } +} + +// impl<'a> Into<[f32;3]> for &'a Units { +// fn into(self) -> [f32; 3] { +// [self[0] as f32,self[1] as f32,self[2] as f32] +// } +// } +// +// impl<'a> Into<(f64,f64,f64)> for &'a Units { +// fn into(self) -> (f64,f64,f64) { +// (self[0],self[1],self[2]) +// } +// } +// impl<'a> Into<(f32,f32,f32)> for &'a Units { +// fn into(self) -> (f32,f32,f32) { +// (self[0] as f32,self[1] as f32,self[2] as f32) +// } +// } + diff -Nru rust-colorsys-0.5.7/src/units/iter.rs rust-colorsys-0.6.5/src/units/iter.rs --- rust-colorsys-0.5.7/src/units/iter.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/src/units/iter.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,65 @@ +use super::Units; + +#[doc(hidden)] +pub struct ColorUnitsIter { + ind: usize, + values: [f64;5], + len: usize, +} + +impl ColorUnitsIter { + pub(crate) fn from_units(units: &Units) -> ColorUnitsIter { + let mut values = [0.0;5]; + for i in 0..units.len { + values[i] = units.list[i].value; + } + + let mut len = units.len; + if let Some(a) = units.alpha.get() { + values[len] = a; + len += 1; + } + + ColorUnitsIter { ind: 0, values, len } + } +} + + +impl core::iter::Iterator for ColorUnitsIter { + type Item = f64; + fn next(&mut self) -> Option { + if self.ind == self.len { return None } + let v = self.values[self.ind]; + self.ind += 1; + Some(v) + } +} + + +#[cfg(test)] +mod test { + use crate::Rgb; + + #[test] + fn color_iter_collect_test() { + let rgb = Rgb::new(1.0,2.0,3.0, None); + let v: Vec = rgb.iter().collect(); + assert_eq!(v, vec![1.0,2.0,3.0]); + + let rgba = Rgb::new(1.0,2.0,3.0, Some(0.5)); + let v: Vec = rgba.iter().collect(); + assert_eq!(v, vec![1.0,2.0,3.0, 0.5]); + } + + #[test] + fn color_iter_test() { + let rgb = Rgb::new(1.0,2.0,3.0, None); + let mut n = 1.0; + + for c in &rgb { + assert!(n.eq(&c)); + n += 1.0; + } + + } +} diff -Nru rust-colorsys-0.5.7/src/units/mod.rs rust-colorsys-0.6.5/src/units/mod.rs --- rust-colorsys-0.5.7/src/units/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/src/units/mod.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,134 @@ +use core::ops::{Add, Index, Sub}; + +pub(crate) use alpha::Alpha; +pub(crate) use unit::Unit; + +use crate::{ApproxEq, DEFAULT_APPROX_EQ_PRECISION}; +use crate::common::approx::approx; + +mod unit; +mod alpha; +mod into; +pub mod iter; + +pub trait GetColorUnits { + fn get_units(&self) -> &Units; + fn get_units_mut(&mut self) -> &mut Units; +} + + +#[derive(Clone, PartialEq, Debug)] +pub struct Units { + pub(crate) len: usize, + pub(crate) list: [Unit; 4], + pub(crate) alpha: Alpha, +} + +impl Units { + pub(crate) fn restrict(&mut self) { + for i in 0..self.len { + self.list[i].restrict(); + } + } + + fn add_sub(&self, other: &Units, is_add: bool) -> Self { + let mut new = self.clone(); + for i in 0..self.len { + let a = new.list[i]; + let b = other.list[i]; + let x = if is_add { a + b } else { a - b }; + new.list[i] = x; + } + new + } + + pub(crate) fn as_ratio(&self) -> Self { + let mut new = self.clone(); + for i in 0..new.len { + new.list[i].turn_into_ratio(); + } + new + } + + pub(crate) fn max(&self) -> (f64, usize) { + self.min_max(true) + } + pub(crate) fn min(&self) -> (f64, usize) { + self.min_max(false) + } + + fn min_max(&self, need_max: bool) -> (f64, usize) { + let mut result = self.list[0].value; + let mut ind = 0; + if self.len != 1 { + for i in 1..self.len { + let v = self.list[i].value; + let is_fit = if need_max { v > result } else { v < result }; + if is_fit { + result = v; + ind = i; + } + } + } + (result, ind) + } + + + pub(crate) fn new_ratios(values: &[f64]) -> Units { + if values.len() > 4 { panic!("length of units values is more than 4") } + let mut ul: [Unit; 4] = Default::default(); + for (ind, v) in values.iter().enumerate() { + ul[ind].set(*v); + } + Units { len: values.len(), list: ul, alpha: Alpha::default() } + } +} + + +impl Index for Units { + type Output = f64; + + fn index(&self, ind: usize) -> &Self::Output { + &self.list[ind].value + } +} + +impl<'a> Add for &'a Units { + type Output = Units; + fn add(self, rhs: &'a Units) -> Self::Output { + self.add_sub(rhs, true) + } +} + +impl<'a> Sub for &'a Units { + type Output = Units; + fn sub(self, rhs: &'a Units) -> Self::Output { + self.add_sub(rhs, false) + } +} + + +impl ApproxEq for Units { + fn approx_eq(&self, other: &Units) -> bool { + self.approx_eq_clarify(other, DEFAULT_APPROX_EQ_PRECISION) + } + + fn approx_eq_clarify(&self, other: &Units, precision: f64) -> bool { + if !self.alpha.approx_eq_clarify(&other.alpha, precision) { + return false + } + for i in 0..self.len { + if !approx(self.list[i].value, other.list[i].value, precision) { + return false + } + } + true + } +} + + +#[cfg(test)] +mod test { + #[test] + fn test() {} +} diff -Nru rust-colorsys-0.5.7/src/units/unit.rs rust-colorsys-0.6.5/src/units/unit.rs --- rust-colorsys-0.5.7/src/units/unit.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/src/units/unit.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,113 @@ +use core::fmt; +use core::ops::{Add, Sub}; + +use crate::consts::{ALL_MIN, HUE_MAX, PERCENT_MAX, RATIO_MAX, RGB_UNIT_MAX}; + +#[derive(Clone, Copy)] +pub struct Unit { + pub(crate) value: f64, + highest: &'static f64 +} + + +impl Default for Unit { + fn default() -> Self { + Unit::new_ratio(0.0 ) + } +} + + +impl fmt::Debug for Unit { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ColorUnit") + .field("value", &self.value) + .finish() + } +} + +impl PartialEq for Unit { + fn eq(&self, other: &Self) -> bool { + self.value.eq(&other.value) + } +} + + +impl Unit { + fn new(value: f64, highest: &'static f64) -> Self { + Unit { + value, + highest + } + } + fn new_checked(value: f64, highest: &'static f64) -> Self { + let mut u = Unit::new(value, highest); + u.restrict(); + u + } + + pub(crate) fn set(&mut self, v: f64) { + self.value = self.get_restricted(v); + } + + pub(crate) fn new_rgb(v: f64) -> Self { + Unit::new(v, &RGB_UNIT_MAX) + } + pub(crate) fn new_hue(v: f64) -> Self { + Unit::new(v, &HUE_MAX) + } + pub(crate) fn new_percent(v: f64) -> Self { + Unit::new(v, &PERCENT_MAX) + } + pub(crate) fn new_ratio(v: f64) -> Self { + Unit::new(v, &RATIO_MAX) + } + + fn get_restricted(&self, val: f64) -> f64 { + if val < ALL_MIN { + return ALL_MIN; + } else if &val > self.highest { + return *self.highest; + } + val + } + + pub(crate) fn restrict(&mut self) { + self.value = self.get_restricted(self.value); + } + + pub(crate) fn turn_into_ratio(&mut self) { + self.value /= self.highest; + self.highest = &RATIO_MAX; + } + + pub(crate) fn turn_into_whole(&mut self, highest: &'static f64) { + self.highest = highest; + self.value *= self.highest; + } + + pub(crate) fn increase(&mut self, v: f64) { + self.set(self.value + v) + } +} + + +impl Add for Unit { + type Output = Unit; + fn add(self, rhs: Self) -> Self::Output { + Unit::new_checked(self.value + rhs.value, self.highest) + } +} + + +impl Sub for Unit { + type Output = Unit; + fn sub(self, rhs: Self) -> Self::Output { + Unit::new_checked(self.value - rhs.value, self.highest) + } +} + +#[cfg(test)] +mod test { + #[test] + fn test() {} +} diff -Nru rust-colorsys-0.5.7/tests/integration_test.rs rust-colorsys-0.6.5/tests/integration_test.rs --- rust-colorsys-0.5.7/tests/integration_test.rs 2020-08-26 20:25:36.000000000 +0000 +++ rust-colorsys-0.6.5/tests/integration_test.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ -#[allow(unused_imports)] -use colorsys::{prelude::*, Hsl, Rgb}; - -#[test] -fn for_docs() { - // let mut rgb1 = Rgb::from((100.0, 255.0, 17.0)); // Rgb { r: 100.0, g: 255.0, b: 17.0, a: None } - // println!(">>> {:?}", rgb1); - // let green = rgb1.get_green(); // 255.0 - // println!(">>> {:?}", green); - - // rgb1.set_red(108.3); // Rgb { r: 108.0, g: 255.0, b: 17.0, a: None } - // println!(">>> {:?}", rgb1); - - // let mut hsl: Hsl = rgb1.into(); - // println!(">>> {:?}", hsl); - - // hsl.saturate( SaturationInSpace::Hsl(-57.901) ); - // println!(">>> {:?}", hsl); - - // let mut rgb2 = Rgb::from(&hsl); - // println!(">>> {:?}", rgb2); - - // let rgb2tuple: (f64,f64,f64) = rgb2.as_ref().into(); - // println!("<><><>{:?}", rgb2tuple); - - // rgb2 += Rgb::from_hex_str("#35f15b").unwrap(); - - // println!(">>> {:?}", rgb2); - // rgb2.set_green(-150.0); - - // rgb2.lighten(-13.123); - // println!(">>> {:?}", rgb2); - - // rgb2.grayscale_simple(); - // println!(">>> GR {:?}", rgb2); - - // let css_string = rgb2.to_css_string(); - // println!(">>> CSS {:?}", css_string); - - // assert_eq!(rgb2.to_css_string(), ""); -} diff -Nru rust-colorsys-0.5.7/tests/tst.rs rust-colorsys-0.6.5/tests/tst.rs --- rust-colorsys-0.5.7/tests/tst.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-colorsys-0.6.5/tests/tst.rs 1973-11-29 21:33:09.000000000 +0000 @@ -0,0 +1,53 @@ +#[allow(unused_imports)] +use colorsys::{prelude::*, Hsl, Rgb}; + +#[test] +fn for_docs() { + use colorsys::{Rgb, Hsl}; + + let rbga_tuple = (57.3, 12.7, 53.0, 0.33); + let rgba = Rgb::from(&rbga_tuple); + let hsla: Hsl = rgba.as_ref().into(); +// ~Hsl { h: 305.78, s: 63.71, l: 13.73, a: 0.33 } + + let rgb_arr: [u8; 3] = Rgb::from(&hsla).into(); +// ~[57, 13, 53] + + let hsla_tuple: (f64,f64,f64,f64) = Hsl::from( Rgb::from(rgb_arr) ).into(); +// ~Hsl { h: 305.78, s: 63.71, l: 13.73, a: 1 } + + let hex: String = rgba.to_hex_string(); +// #390d35 + + +// From/Into + + let rgb1 = Rgb::from_hex_str("37ea4c").unwrap(); + + let rgb2 = Rgb::from( + Into::<[f32; 4]>::into(Rgb::from( + Into::<[u16; 3]>::into( + Rgb::from( + Into::<(i32,i32,i32)>::into( + Rgb::from( + Into::<[i64; 3]>::into(&rgb1) + ) + ) + ) + ) + )) + ); + + assert_eq!(rgb1, rgb2); + // +// Ratio +// + use colorsys::{RgbRatio, ApproxEq}; + let blue = Rgb::from([34, 111, 235]); + + let ratio: [f32; 4] = blue.as_ratio().into(); +// ~[0.133, 0.435, 0.922, 1.0] + + let converted: Rgb = RgbRatio::from(&ratio).into(); + assert!(blue.approx_eq_clarify(&converted, 0.0001)); +}