Skip to content

Commit

Permalink
chore(argb, rgb, xyz, lab): created structs for them
Browse files Browse the repository at this point in the history
chore(tests): update theme test
  • Loading branch information
Aiving committed Mar 14, 2024
1 parent 09bd344 commit 35e58a0
Show file tree
Hide file tree
Showing 15 changed files with 505 additions and 573 deletions.
117 changes: 32 additions & 85 deletions src/dynamic_color/dynamic_scheme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::hct::Hct;
use crate::palettes::tonal::TonalPalette;
use crate::utils::color::Argb;
use crate::utils::math::sanitize_degrees_double;
use crate::utils::string::hex_from_argb;

use super::material_dynamic_colors::MaterialDynamicColors;
use super::variant::Variant;
Expand Down Expand Up @@ -300,99 +299,47 @@ impl PartialEq for DynamicScheme {
impl fmt::Display for DynamicScheme {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Scheme {{")?;
writeln!(f, " primary = #{}", hex_from_argb(&self.primary()))?;
writeln!(f, " on_primary = #{}", hex_from_argb(&self.on_primary()))?;
writeln!(f, " primary = {}", self.primary())?;
writeln!(f, " on_primary = {}", self.on_primary())?;
writeln!(f, " primary_container = {}", self.primary_container())?;
writeln!(
f,
" primary_container = #{}",
hex_from_argb(&self.primary_container())
" on_primary_container = {}",
self.on_primary_container()
)?;
writeln!(f, " secondary = {}", self.secondary())?;
writeln!(f, " on_secondary = {}", self.on_secondary())?;
writeln!(f, " secondary_container = {}", self.secondary_container())?;
writeln!(
f,
" on_primary_container = #{}",
hex_from_argb(&self.on_primary_container())
" on_secondary_container = {}",
self.on_secondary_container()
)?;
writeln!(f, " secondary = #{}", hex_from_argb(&self.secondary()))?;
writeln!(f, " tertiary = {}", self.tertiary())?;
writeln!(f, " on_tertiary = {}", self.on_tertiary())?;
writeln!(f, " tertiary_container = {}", self.tertiary_container())?;
writeln!(
f,
" on_secondary = #{}",
hex_from_argb(&self.on_secondary())
)?;
writeln!(
f,
" secondary_container = #{}",
hex_from_argb(&self.secondary_container())
)?;
writeln!(
f,
" on_secondary_container = #{}",
hex_from_argb(&self.on_secondary_container())
)?;
writeln!(f, " tertiary = #{}", hex_from_argb(&self.tertiary()))?;
writeln!(f, " on_tertiary = #{}", hex_from_argb(&self.on_tertiary()))?;
writeln!(
f,
" tertiary_container = #{}",
hex_from_argb(&self.tertiary_container())
)?;
writeln!(
f,
" on_tertiary_container = #{}",
hex_from_argb(&self.on_tertiary_container())
)?;
writeln!(f, " error = #{}", hex_from_argb(&self.error()))?;
writeln!(f, " on_error = #{}", hex_from_argb(&self.on_error()))?;
writeln!(
f,
" error_container = #{}",
hex_from_argb(&self.error_container())
)?;
writeln!(
f,
" on_error_container = #{}",
hex_from_argb(&self.on_error_container())
)?;
writeln!(f, " background = #{}", hex_from_argb(&self.background()))?;
writeln!(
f,
" on_background = #{}",
hex_from_argb(&self.on_background())
)?;
writeln!(f, " surface = #{}", hex_from_argb(&self.surface()))?;
writeln!(f, " on_surface = #{}", hex_from_argb(&self.on_surface()))?;
writeln!(
f,
" surface_variant = #{}",
hex_from_argb(&self.surface_variant())
)?;
writeln!(
f,
" on_surface_variant = #{}",
hex_from_argb(&self.on_surface_variant())
)?;
writeln!(f, " outline = #{}", hex_from_argb(&self.outline()))?;
writeln!(
f,
" outline_variant = #{}",
hex_from_argb(&self.outline_variant())
)?;
writeln!(f, " shadow = #{}", hex_from_argb(&self.shadow()))?;
writeln!(f, " scrim = #{}", hex_from_argb(&self.scrim()))?;
writeln!(
f,
" inverse_surface = #{}",
hex_from_argb(&self.inverse_surface())
)?;
writeln!(
f,
" inverse_on_surface = #{}",
hex_from_argb(&self.inverse_on_surface())
)?;
writeln!(
f,
" inverse_primary = #{}",
hex_from_argb(&self.inverse_primary())
" on_tertiary_container = {}",
self.on_tertiary_container()
)?;
writeln!(f, " error = {}", self.error())?;
writeln!(f, " on_error = {}", self.on_error())?;
writeln!(f, " error_container = {}", self.error_container())?;
writeln!(f, " on_error_container = {}", self.on_error_container())?;
writeln!(f, " background = {}", self.background())?;
writeln!(f, " on_background = {}", self.on_background())?;
writeln!(f, " surface = {}", self.surface())?;
writeln!(f, " on_surface = {}", self.on_surface())?;
writeln!(f, " surface_variant = {}", self.surface_variant())?;
writeln!(f, " on_surface_variant = {}", self.on_surface_variant())?;
writeln!(f, " outline = {}", self.outline())?;
writeln!(f, " outline_variant = {}", self.outline_variant())?;
writeln!(f, " shadow = {}", self.shadow())?;
writeln!(f, " scrim = {}", self.scrim())?;
writeln!(f, " inverse_surface = {}", self.inverse_surface())?;
writeln!(f, " inverse_on_surface = {}", self.inverse_on_surface())?;
writeln!(f, " inverse_primary = {}", self.inverse_primary())?;
writeln!(f, "}}")
}
}
Expand Down
17 changes: 8 additions & 9 deletions src/hct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use core::hash::Hasher;
#[cfg(feature = "serde")]
use serde::Serialize;

use crate::utils::color::lstar_from_argb;
use crate::utils::color::lstar_from_y;
use crate::utils::color::Argb;

Expand Down Expand Up @@ -55,7 +54,7 @@ impl Hct {

self._hue = cam16.hue;
self._chroma = cam16.chroma;
self._tone = lstar_from_argb(&self._argb);
self._tone = self._argb.as_lstar();
}

/// 0 <= [newChroma] <= ?
Expand All @@ -79,7 +78,7 @@ impl Hct {

self._hue = cam16.hue;
self._chroma = cam16.chroma;
self._tone = lstar_from_argb(&self._argb);
self._tone = self._argb.as_lstar();
}

/// Lightness. Ranges from 0 to 100.
Expand Down Expand Up @@ -107,7 +106,7 @@ impl Hct {

self._hue = cam16.hue;
self._chroma = cam16.chroma;
self._tone = lstar_from_argb(&self._argb);
self._tone = self._argb.as_lstar();
}

pub fn new(argb: Argb) -> Self {
Expand All @@ -117,7 +116,7 @@ impl Hct {

let _hue = cam16.hue;
let _chroma = cam16.chroma;
let _tone = lstar_from_argb(&argb);
let _tone = argb.as_lstar();

Self {
_hue,
Expand Down Expand Up @@ -157,9 +156,9 @@ impl Hct {

// 2. Create CAM16 of those Xyz coordinates in default VC.
let recast_in_vc = Cam16::from_xyz_in_viewing_conditions(
viewed_in_vc[0],
viewed_in_vc[1],
viewed_in_vc[2],
viewed_in_vc.x,
viewed_in_vc.y,
viewed_in_vc.z,
ViewingConditions::standard(),
);

Expand All @@ -169,7 +168,7 @@ impl Hct {
Hct::from(
recast_in_vc.hue,
recast_in_vc.chroma,
lstar_from_y(viewed_in_vc[1]),
lstar_from_y(viewed_in_vc.y),
)
}
}
Expand Down
11 changes: 3 additions & 8 deletions src/hct/cam16.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use core::f64::consts::PI;

use crate::utils::color::argb_from_xyz;
use crate::utils::color::xyz_from_argb;
use crate::utils::color::Argb;
use crate::utils::color::Xyz;

Expand Down Expand Up @@ -86,10 +84,7 @@ impl Cam16 {
viewing_conditions: ViewingConditions,
) -> Cam16 {
// Transform Argb int to Xyz
let xyz = xyz_from_argb(&argb);
let x = xyz[0];
let y = xyz[1];
let z = xyz[2];
let Xyz { x, y, z } = Xyz::from(argb);

Cam16::from_xyz_in_viewing_conditions(x, y, z, viewing_conditions)
}
Expand Down Expand Up @@ -259,7 +254,7 @@ impl Cam16 {
pub fn viewed(&self, viewing_conditions: ViewingConditions) -> Argb {
let xyz = self.xyz_in_viewing_conditions(viewing_conditions);

argb_from_xyz(xyz)
xyz.into()
}

/// Xyz representation of CAM16 seen in [viewing_conditions].
Expand Down Expand Up @@ -305,7 +300,7 @@ impl Cam16 {
let y = 0.38752654 * r_f + 0.62144744 * g_f - 0.00897398 * b_f;
let z = -0.01584150 * r_f - 0.03412294 * g_f + 1.04996444 * b_f;

[x, y, z]
Xyz::new(x, y, z)
}
}

Expand Down
31 changes: 16 additions & 15 deletions src/hct/solver.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use core::f64::consts::PI;

use crate::utils::color::argb_from_linrgb;
use crate::utils::color::argb_from_lstar;
use crate::utils::color::y_from_lstar;
use crate::utils::color::Argb;
use crate::utils::color::LinearRgb;
use crate::utils::math::matrix_multiply;
use crate::utils::math::sanitize_degrees_double;

Expand Down Expand Up @@ -604,38 +603,39 @@ impl HctSolver {
let r_cscaled = Self::inverse_chromatic_adaptation(r_a);
let g_cscaled = Self::inverse_chromatic_adaptation(g_a);
let b_cscaled = Self::inverse_chromatic_adaptation(b_a);
let linrgb = matrix_multiply(
let [red, green, blue] = matrix_multiply(
[r_cscaled, g_cscaled, b_cscaled],
LINRGB_FROM_SCALED_DISCOUNT,
);
let linrgb = LinearRgb { red, green, blue };
// ===========================================================
// Operations inlined from Cam16 to avoid repeated calculation
// ===========================================================
if linrgb[0] < 0.0 || linrgb[1] < 0.0 || linrgb[2] < 0.0 {
return [0; 4];
if linrgb.red < 0.0 || linrgb.green < 0.0 || linrgb.blue < 0.0 {
return Argb::default();
}

let [k_r, k_g, k_b] = Y_FROM_LINRGB;
let fnj = k_r * linrgb[0] + k_g * linrgb[1] + k_b * linrgb[2];
let fnj = k_r * linrgb.red + k_g * linrgb.green + k_b * linrgb.blue;

if fnj <= 0.0 {
return [0; 4];
return Argb::default();
}

if iteration_round == 4 || (fnj - y).abs() < 0.002 {
if linrgb[0] > 100.01 || linrgb[1] > 100.01 || linrgb[2] > 100.01 {
return [0; 4];
if linrgb.red > 100.01 || linrgb.green > 100.01 || linrgb.blue > 100.01 {
return Argb::default();
}

return argb_from_linrgb(linrgb);
return linrgb.into();
}

// Iterates with Newton method,
// Using 2 * fn(j) / j as the approximation of fn'(j)
j = j - (fnj - y) * j / (2.0 * fnj);
}

[0; 4]
Argb::default()
}

/// Finds an sRgb color with the given hue, chroma, and L*, if
Expand All @@ -648,7 +648,7 @@ impl HctSolver {
/// chroma will be maximized.
pub fn solve_to_int(hue_degrees: f64, chroma: f64, lstar: f64) -> Argb {
if chroma < 0.0001 || !(0.0001..=99.9999).contains(&lstar) {
return argb_from_lstar(lstar);
return Argb::from_lstar(lstar);
}

let hue_degrees = sanitize_degrees_double(hue_degrees);
Expand All @@ -658,13 +658,14 @@ impl HctSolver {

let exact_answer = Self::find_result_by_j(hue_radians, chroma, y);

if exact_answer != [0; 4] {
if exact_answer != Argb::default() {
return exact_answer;
}

let linrgb = Self::bisect_to_limit(y, hue_radians);
let [red, green, blue] = Self::bisect_to_limit(y, hue_radians);
let linrgb = LinearRgb { red, green, blue };

argb_from_linrgb(linrgb)
linrgb.into()
}

/// Finds a CAM16 object with the given hue, chroma, and L*, if
Expand Down
2 changes: 0 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ pub use utils::image::Image;
#[cfg(feature = "image")]
pub use utils::image::ImageReader;

pub use utils::string::argb_from_hex;
pub use utils::string::hex_from_argb;
pub use utils::theme::theme_from_source_color;

pub use palettes::core::CorePalette;
Expand Down
12 changes: 3 additions & 9 deletions src/quantize/point_provider_lab.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use crate::utils::color::argb_from_lab;
use crate::utils::color::lab_from_argb;
use crate::utils::color::Argb;
use crate::utils::color::Lab;

Expand All @@ -9,25 +7,21 @@ pub struct PointProviderLab;

impl PointProvider for PointProviderLab {
fn lab_from_int(&self, argb: &Argb) -> Lab {
lab_from_argb(argb)
(*argb).into()
}

fn lab_to_int(&self, lab: &Lab) -> Argb {
argb_from_lab(lab)
(*lab).into()
}

fn distance(&self, one: &Lab, two: &Lab) -> f64 {
let d_l = one[0] - two[0];
let d_a = one[1] - two[1];
let d_b = one[2] - two[2];

// Standard CIE 1976 delta E formula also takes the square root, unneeded
// here. This method is used by quantization algorithms to compare distance,
// and the relative ordering is the same, with or without a square root.

// This relatively minor optimization is helpful because this method is
// called at least once for each pixel in an image.
d_l.powi(2) + d_a.powi(2) + d_b.powi(2)
(one.l - two.l).powi(2) + (one.a - two.a).powi(2) + (one.b - two.b).powi(2)
}

fn new() -> Self {
Expand Down
Loading

0 comments on commit 35e58a0

Please sign in to comment.