分拆根文件中的功能函数。
This commit is contained in:
		
							
								
								
									
										190
									
								
								color-module/src/analysis.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								color-module/src/analysis.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,190 @@ | ||||
| use std::str::FromStr; | ||||
|  | ||||
| use palette::{ | ||||
|     cam16::{Cam16Jch, Parameters}, | ||||
|     FromColor, Hsl, IntoColor, Oklch, Srgb, | ||||
| }; | ||||
| use wasm_bindgen::prelude::wasm_bindgen; | ||||
|  | ||||
| use crate::{ | ||||
|     color_differ::{self, ColorDifference}, | ||||
|     errors, reversing, | ||||
| }; | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn differ_in_rgb( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::rgb::RGBDifference, errors::ColorError> { | ||||
|     let srgb = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let other_srgb = Srgb::from_str(other) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     Ok(srgb.difference(&other_srgb)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn relative_differ_in_rgb( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::rgb::RGBDifference, errors::ColorError> { | ||||
|     let srgb = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let other_srgb = Srgb::from_str(other) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     Ok(srgb.difference_relative(&other_srgb)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn differ_in_hsl( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::hsl::HSLDifference, errors::ColorError> { | ||||
|     let hsl = Hsl::from_color( | ||||
|         Srgb::from_str(color) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     let other_hsl = Hsl::from_color( | ||||
|         Srgb::from_str(other) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     Ok(hsl.difference(&other_hsl)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn relative_differ_in_hsl( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::hsl::HSLDifference, errors::ColorError> { | ||||
|     let hsl = Hsl::from_color( | ||||
|         Srgb::from_str(color) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     let other_hsl = Hsl::from_color( | ||||
|         Srgb::from_str(other) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     Ok(hsl.difference_relative(&other_hsl)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn differ_in_hct( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::cam16jch::HctDiffference, errors::ColorError> { | ||||
|     let hct = Cam16Jch::from_xyz( | ||||
|         Srgb::from_str(color) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|             .into_format::<f32>() | ||||
|             .into_color(), | ||||
|         Parameters::default_static_wp(40.0), | ||||
|     ); | ||||
|     let other_hct = Cam16Jch::from_xyz( | ||||
|         Srgb::from_str(other) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|             .into_format::<f32>() | ||||
|             .into_color(), | ||||
|         Parameters::default_static_wp(40.0), | ||||
|     ); | ||||
|     Ok(hct.difference(&other_hct)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn relative_differ_in_hct( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::cam16jch::HctDiffference, errors::ColorError> { | ||||
|     let hct = Cam16Jch::from_xyz( | ||||
|         Srgb::from_str(color) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|             .into_format::<f32>() | ||||
|             .into_color(), | ||||
|         Parameters::default_static_wp(40.0), | ||||
|     ); | ||||
|     let other_hct = Cam16Jch::from_xyz( | ||||
|         Srgb::from_str(other) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|             .into_format::<f32>() | ||||
|             .into_color(), | ||||
|         Parameters::default_static_wp(40.0), | ||||
|     ); | ||||
|     Ok(hct.difference_relative(&other_hct)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn differ_in_oklch( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::oklch::OklchDifference, errors::ColorError> { | ||||
|     let oklch = Oklch::from_color( | ||||
|         Srgb::from_str(color) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     let other_oklch = Oklch::from_color( | ||||
|         Srgb::from_str(other) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     Ok(oklch.difference(&other_oklch)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn relative_differ_in_oklch( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::oklch::OklchDifference, errors::ColorError> { | ||||
|     let oklch = Oklch::from_color( | ||||
|         Srgb::from_str(color) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     let other_oklch = Oklch::from_color( | ||||
|         Srgb::from_str(other) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     Ok(oklch.difference_relative(&other_oklch)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn tint_scale( | ||||
|     basic_color: &str, | ||||
|     mixed_color: &str, | ||||
| ) -> Result<reversing::MixReversing, errors::ColorError> { | ||||
|     let basic_color = Srgb::from_str(basic_color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(basic_color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let mixed_color = Srgb::from_str(mixed_color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(mixed_color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     Ok(reversing::MixReversing::from_tint_rgb( | ||||
|         basic_color, | ||||
|         mixed_color, | ||||
|     )) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn shade_scale( | ||||
|     basic_color: &str, | ||||
|     mixed_color: &str, | ||||
| ) -> Result<reversing::MixReversing, errors::ColorError> { | ||||
|     let basic_color = Srgb::from_str(basic_color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(basic_color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let mixed_color = Srgb::from_str(mixed_color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(mixed_color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     Ok(reversing::MixReversing::from_shade_rgb( | ||||
|         basic_color, | ||||
|         mixed_color, | ||||
|     )) | ||||
| } | ||||
| @@ -1,7 +1,8 @@ | ||||
| use std::sync::LazyLock; | ||||
| use std::{str::FromStr, sync::LazyLock}; | ||||
|  | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use strum::{Display, EnumIter, EnumString}; | ||||
| use strum::{Display, EnumIter, EnumString, IntoEnumIterator}; | ||||
| use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; | ||||
|  | ||||
| #[derive(Debug, Clone, Serialize, Deserialize)] | ||||
| pub struct ColorDescription { | ||||
| @@ -87,3 +88,45 @@ impl Category { | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn color_categories() -> Result<JsValue, String> { | ||||
|     let categories = Category::iter() | ||||
|         .map(|variant| { | ||||
|             serde_json::json!({ | ||||
|                 "label": variant.label(), | ||||
|                 "value": variant.to_string(), | ||||
|             }) | ||||
|         }) | ||||
|         .collect::<Vec<_>>(); | ||||
|  | ||||
|     serde_wasm_bindgen::to_value(&categories).map_err(|e| e.to_string()) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn search_color_cards(tag: String, category: Option<String>) -> Result<JsValue, String> { | ||||
|     let selected_category = category.and_then(|c| Category::from_str(&c).ok()); | ||||
|     let all_cards = &*COLOR_CARDS; | ||||
|     let mut cards = all_cards | ||||
|         .iter() | ||||
|         .filter(|card| card.tags.contains(&tag)) | ||||
|         .filter(|card| { | ||||
|             if let Some(category) = &selected_category { | ||||
|                 let card_category = Category::from_oklch(&card.oklch); | ||||
|                 card_category == *category | ||||
|             } else { | ||||
|                 true | ||||
|             } | ||||
|         }) | ||||
|         .collect::<Vec<_>>(); | ||||
|  | ||||
|     cards.sort_by(|a, b| { | ||||
|         a.oklch[2] | ||||
|             .partial_cmp(&b.oklch[2]) | ||||
|             .or_else(|| a.oklch[1].partial_cmp(&b.oklch[1])) | ||||
|             .or_else(|| a.oklch[0].partial_cmp(&b.oklch[0])) | ||||
|             .unwrap_or(std::cmp::Ordering::Equal) | ||||
|     }); | ||||
|  | ||||
|     serde_wasm_bindgen::to_value(&cards).map_err(|e| e.to_string()) | ||||
| } | ||||
|   | ||||
							
								
								
									
										80
									
								
								color-module/src/color_shifting.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								color-module/src/color_shifting.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| use std::str::FromStr; | ||||
|  | ||||
| use palette::{Darken, FromColor, Lighten, Mix, Oklch, Srgb}; | ||||
| use wasm_bindgen::prelude::wasm_bindgen; | ||||
|  | ||||
| use crate::errors; | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn lighten(color: &str, percent: f32) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let lightened_color = oklch.lighten(percent); | ||||
|     let srgb = Srgb::from_color(lightened_color); | ||||
|     Ok(format!("{:x}", srgb.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn lighten_absolute(color: &str, value: f32) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let lightened_color = oklch.lighten_fixed(value); | ||||
|     let srgb = Srgb::from_color(lightened_color); | ||||
|     Ok(format!("{:x}", srgb.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn darken(color: &str, percent: f32) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let darkened_color = oklch.darken(percent); | ||||
|     let srgb = Srgb::from_color(darkened_color); | ||||
|     Ok(format!("{:x}", srgb.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn darken_absolute(color: &str, value: f32) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let darkened_color = oklch.darken_fixed(value); | ||||
|     let srgb = Srgb::from_color(darkened_color); | ||||
|     Ok(format!("{:x}", srgb.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn mix(color1: &str, color2: &str, percent: f32) -> Result<String, errors::ColorError> { | ||||
|     let srgb1 = Srgb::from_str(color1) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color1.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let srgb2 = Srgb::from_str(color2) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color2.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let mixed_color = srgb1.mix(srgb2, percent); | ||||
|     Ok(format!("{:x}", mixed_color.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn tint(color: &str, percent: f32) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let tinted_color = origin_color.mix(Srgb::new(1.0, 1.0, 1.0), percent); | ||||
|     Ok(format!("{:x}", tinted_color.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn shade(color: &str, percent: f32) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let shaded_color = origin_color.mix(Srgb::new(0.0, 0.0, 0.0), percent); | ||||
|     Ok(format!("{:x}", shaded_color.into_format::<u8>())) | ||||
| } | ||||
| @@ -1,24 +1,24 @@ | ||||
| use std::{str::FromStr, sync::Arc}; | ||||
| use std::str::FromStr; | ||||
|  | ||||
| use color_card::Category; | ||||
| use color_differ::ColorDifference; | ||||
| use palette::{ | ||||
|     cam16::{Cam16Jch, Parameters}, | ||||
|     color_difference::Wcag21RelativeContrast, | ||||
|     color_theory::*, | ||||
|     convert::FromColorUnclamped, | ||||
|     Darken, FromColor, Hsl, IntoColor, IsWithinBounds, Lab, Lighten, Mix, Oklch, ShiftHue, Srgb, | ||||
|     FromColor, Hsl, IntoColor, IsWithinBounds, Lab, Oklch, Srgb, | ||||
| }; | ||||
| use strum::IntoEnumIterator; | ||||
| use wasm_bindgen::prelude::*; | ||||
|  | ||||
| mod analysis; | ||||
| mod color_card; | ||||
| mod color_differ; | ||||
| mod color_shifting; | ||||
| mod convert; | ||||
| mod errors; | ||||
| mod palettes; | ||||
| mod reversing; | ||||
| mod schemes; | ||||
| mod series; | ||||
| mod theory; | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn represent_rgb(color: &str) -> Result<Box<[u8]>, errors::ColorError> { | ||||
| @@ -125,91 +125,6 @@ pub fn hct_to_hex(hue: f32, chroma: f32, tone: f32) -> Result<String, errors::Co | ||||
|     Ok(format!("{:x}", srgb.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn shift_hue(color: &str, degree: f32) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let shifted_color = oklch.shift_hue(degree); | ||||
|     let srgb = Srgb::from_color(shifted_color); | ||||
|     Ok(format!("{:x}", srgb.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn lighten(color: &str, percent: f32) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let lightened_color = oklch.lighten(percent); | ||||
|     let srgb = Srgb::from_color(lightened_color); | ||||
|     Ok(format!("{:x}", srgb.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn lighten_absolute(color: &str, value: f32) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let lightened_color = oklch.lighten_fixed(value); | ||||
|     let srgb = Srgb::from_color(lightened_color); | ||||
|     Ok(format!("{:x}", srgb.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn darken(color: &str, percent: f32) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let darkened_color = oklch.darken(percent); | ||||
|     let srgb = Srgb::from_color(darkened_color); | ||||
|     Ok(format!("{:x}", srgb.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn darken_absolute(color: &str, value: f32) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let darkened_color = oklch.darken_fixed(value); | ||||
|     let srgb = Srgb::from_color(darkened_color); | ||||
|     Ok(format!("{:x}", srgb.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn mix(color1: &str, color2: &str, percent: f32) -> Result<String, errors::ColorError> { | ||||
|     let srgb1 = Srgb::from_str(color1) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color1.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let srgb2 = Srgb::from_str(color2) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color2.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let mixed_color = srgb1.mix(srgb2, percent); | ||||
|     Ok(format!("{:x}", mixed_color.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn tint(color: &str, percent: f32) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let tinted_color = origin_color.mix(Srgb::new(1.0, 1.0, 1.0), percent); | ||||
|     Ok(format!("{:x}", tinted_color.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn shade(color: &str, percent: f32) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let shaded_color = origin_color.mix(Srgb::new(0.0, 0.0, 0.0), percent); | ||||
|     Ok(format!("{:x}", shaded_color.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn wacg_relative_contrast(fg_color: &str, bg_color: &str) -> Result<f32, errors::ColorError> { | ||||
|     let fg_srgb = Srgb::from_str(fg_color) | ||||
| @@ -220,389 +135,3 @@ pub fn wacg_relative_contrast(fg_color: &str, bg_color: &str) -> Result<f32, err | ||||
|         .into_format::<f32>(); | ||||
|     Ok(fg_srgb.relative_contrast(bg_srgb)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn analogous_30(color: &str) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let (color_n30, color_p30) = oklch.analogous(); | ||||
|     let srgb_n30 = Srgb::from_color(color_n30); | ||||
|     let srgb_p30 = Srgb::from_color(color_p30); | ||||
|     Ok(vec![ | ||||
|         format!("{:x}", srgb_n30.into_format::<u8>()), | ||||
|         format!("{:x}", srgb_p30.into_format::<u8>()), | ||||
|     ]) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn analogous_60(color: &str) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let (color_n60, color_p60) = oklch.analogous_secondary(); | ||||
|     let srgb_n60 = Srgb::from_color(color_n60); | ||||
|     let srgb_p60 = Srgb::from_color(color_p60); | ||||
|     Ok(vec![ | ||||
|         format!("{:x}", srgb_n60.into_format::<u8>()), | ||||
|         format!("{:x}", srgb_p60.into_format::<u8>()), | ||||
|     ]) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn complementary(color: &str) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let complementary_color = oklch.complementary(); | ||||
|     let srgb = Srgb::from_color(complementary_color); | ||||
|     Ok(format!("{:x}", srgb.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn split_complementary(color: &str) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let (color_p150, color_p210) = oklch.split_complementary(); | ||||
|     let srgb_p150 = Srgb::from_color(color_p150); | ||||
|     let srgb_p210 = Srgb::from_color(color_p210); | ||||
|     Ok(vec![ | ||||
|         format!("{:x}", srgb_p150.into_format::<u8>()), | ||||
|         format!("{:x}", srgb_p210.into_format::<u8>()), | ||||
|     ]) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn tetradic(color: &str) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let (color_p90, color_p180, color_p270) = oklch.tetradic(); | ||||
|     let srgb_p90 = Srgb::from_color(color_p90); | ||||
|     let srgb_p180 = Srgb::from_color(color_p180); | ||||
|     let srgb_p270 = Srgb::from_color(color_p270); | ||||
|     Ok(vec![ | ||||
|         format!("{:x}", srgb_p90.into_format::<u8>()), | ||||
|         format!("{:x}", srgb_p180.into_format::<u8>()), | ||||
|         format!("{:x}", srgb_p270.into_format::<u8>()), | ||||
|     ]) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn triadic(color: &str) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let (color_p120, color_p240) = oklch.triadic(); | ||||
|     let srgb_p120 = Srgb::from_color(color_p120); | ||||
|     let srgb_p240 = Srgb::from_color(color_p240); | ||||
|     Ok(vec![ | ||||
|         format!("{:x}", srgb_p120.into_format::<u8>()), | ||||
|         format!("{:x}", srgb_p240.into_format::<u8>()), | ||||
|     ]) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn series( | ||||
|     color: &str, | ||||
|     expand_amount: i16, | ||||
|     step: f32, | ||||
| ) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Arc::new(Oklch::from_color(origin_color.clone())); | ||||
|  | ||||
|     let mut color_series = Vec::new(); | ||||
|     for s in (1..=expand_amount).rev() { | ||||
|         let darkened_color = Arc::clone(&oklch).darken(s as f32 * step); | ||||
|         let srgb = Srgb::from_color(darkened_color); | ||||
|         color_series.push(format!("{:x}", srgb.into_format::<u8>())); | ||||
|     } | ||||
|     color_series.push(format!("{:x}", origin_color.into_format::<u8>())); | ||||
|     for s in 1..=expand_amount { | ||||
|         let lightened_color = Arc::clone(&oklch).lighten(s as f32 * step); | ||||
|         let srgb = Srgb::from_color(lightened_color); | ||||
|         color_series.push(format!("{:x}", srgb.into_format::<u8>())); | ||||
|     } | ||||
|     Ok(color_series) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn tonal_lighten_series( | ||||
|     color: &str, | ||||
|     expand_amount: i16, | ||||
|     step: f32, | ||||
| ) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let hct = Cam16Jch::from_xyz( | ||||
|         origin_color.into_color(), | ||||
|         Parameters::default_static_wp(40.0), | ||||
|     ); | ||||
|  | ||||
|     let mut color_series = Vec::new(); | ||||
|     let mut lightness = hct.lightness; | ||||
|     for _ in 1..=expand_amount { | ||||
|         lightness += (100.0 - lightness) * step; | ||||
|         let lightened_color = Cam16Jch::new(lightness, hct.chroma, hct.hue); | ||||
|         let srgb = Srgb::from_color(lightened_color.into_xyz(Parameters::default_static_wp(40.0))); | ||||
|         color_series.push(format!("{:x}", srgb.into_format::<u8>())); | ||||
|     } | ||||
|  | ||||
|     Ok(color_series) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn tonal_darken_series( | ||||
|     color: &str, | ||||
|     expand_amount: i16, | ||||
|     step: f32, | ||||
| ) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let hct = Cam16Jch::from_xyz( | ||||
|         origin_color.into_color(), | ||||
|         Parameters::default_static_wp(40.0), | ||||
|     ); | ||||
|  | ||||
|     let mut color_series = Vec::new(); | ||||
|     let mut lightness = hct.lightness; | ||||
|     for _ in 1..=expand_amount { | ||||
|         lightness *= 1.0 - step; | ||||
|         let darkened_color = Cam16Jch::new(lightness, hct.chroma, hct.hue); | ||||
|         let srgb = Srgb::from_color(darkened_color.into_xyz(Parameters::default_static_wp(40.0))); | ||||
|         color_series.push(format!("{:x}", srgb.into_format::<u8>())); | ||||
|     } | ||||
|  | ||||
|     Ok(color_series.into_iter().rev().collect()) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn color_categories() -> Result<JsValue, String> { | ||||
|     let categories = Category::iter() | ||||
|         .map(|variant| { | ||||
|             serde_json::json!({ | ||||
|                 "label": variant.label(), | ||||
|                 "value": variant.to_string(), | ||||
|             }) | ||||
|         }) | ||||
|         .collect::<Vec<_>>(); | ||||
|  | ||||
|     serde_wasm_bindgen::to_value(&categories).map_err(|e| e.to_string()) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn search_color_cards(tag: String, category: Option<String>) -> Result<JsValue, String> { | ||||
|     let selected_category = category.and_then(|c| Category::from_str(&c).ok()); | ||||
|     let all_cards = &*color_card::COLOR_CARDS; | ||||
|     let mut cards = all_cards | ||||
|         .iter() | ||||
|         .filter(|card| card.tags.contains(&tag)) | ||||
|         .filter(|card| { | ||||
|             if let Some(category) = &selected_category { | ||||
|                 let card_category = Category::from_oklch(&card.oklch); | ||||
|                 card_category == *category | ||||
|             } else { | ||||
|                 true | ||||
|             } | ||||
|         }) | ||||
|         .collect::<Vec<_>>(); | ||||
|  | ||||
|     cards.sort_by(|a, b| { | ||||
|         a.oklch[2] | ||||
|             .partial_cmp(&b.oklch[2]) | ||||
|             .or_else(|| a.oklch[1].partial_cmp(&b.oklch[1])) | ||||
|             .or_else(|| a.oklch[0].partial_cmp(&b.oklch[0])) | ||||
|             .unwrap_or(std::cmp::Ordering::Equal) | ||||
|     }); | ||||
|  | ||||
|     serde_wasm_bindgen::to_value(&cards).map_err(|e| e.to_string()) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn differ_in_rgb( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::rgb::RGBDifference, errors::ColorError> { | ||||
|     let srgb = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let other_srgb = Srgb::from_str(other) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     Ok(srgb.difference(&other_srgb)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn relative_differ_in_rgb( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::rgb::RGBDifference, errors::ColorError> { | ||||
|     let srgb = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let other_srgb = Srgb::from_str(other) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     Ok(srgb.difference_relative(&other_srgb)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn differ_in_hsl( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::hsl::HSLDifference, errors::ColorError> { | ||||
|     let hsl = Hsl::from_color( | ||||
|         Srgb::from_str(color) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     let other_hsl = Hsl::from_color( | ||||
|         Srgb::from_str(other) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     Ok(hsl.difference(&other_hsl)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn relative_differ_in_hsl( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::hsl::HSLDifference, errors::ColorError> { | ||||
|     let hsl = Hsl::from_color( | ||||
|         Srgb::from_str(color) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     let other_hsl = Hsl::from_color( | ||||
|         Srgb::from_str(other) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     Ok(hsl.difference_relative(&other_hsl)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn differ_in_hct( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::cam16jch::HctDiffference, errors::ColorError> { | ||||
|     let hct = Cam16Jch::from_xyz( | ||||
|         Srgb::from_str(color) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|             .into_format::<f32>() | ||||
|             .into_color(), | ||||
|         Parameters::default_static_wp(40.0), | ||||
|     ); | ||||
|     let other_hct = Cam16Jch::from_xyz( | ||||
|         Srgb::from_str(other) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|             .into_format::<f32>() | ||||
|             .into_color(), | ||||
|         Parameters::default_static_wp(40.0), | ||||
|     ); | ||||
|     Ok(hct.difference(&other_hct)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn relative_differ_in_hct( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::cam16jch::HctDiffference, errors::ColorError> { | ||||
|     let hct = Cam16Jch::from_xyz( | ||||
|         Srgb::from_str(color) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|             .into_format::<f32>() | ||||
|             .into_color(), | ||||
|         Parameters::default_static_wp(40.0), | ||||
|     ); | ||||
|     let other_hct = Cam16Jch::from_xyz( | ||||
|         Srgb::from_str(other) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|             .into_format::<f32>() | ||||
|             .into_color(), | ||||
|         Parameters::default_static_wp(40.0), | ||||
|     ); | ||||
|     Ok(hct.difference_relative(&other_hct)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn differ_in_oklch( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::oklch::OklchDifference, errors::ColorError> { | ||||
|     let oklch = Oklch::from_color( | ||||
|         Srgb::from_str(color) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     let other_oklch = Oklch::from_color( | ||||
|         Srgb::from_str(other) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     Ok(oklch.difference(&other_oklch)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn relative_differ_in_oklch( | ||||
|     color: &str, | ||||
|     other: &str, | ||||
| ) -> Result<color_differ::oklch::OklchDifference, errors::ColorError> { | ||||
|     let oklch = Oklch::from_color( | ||||
|         Srgb::from_str(color) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     let other_oklch = Oklch::from_color( | ||||
|         Srgb::from_str(other) | ||||
|             .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? | ||||
|             .into_format::<f32>(), | ||||
|     ); | ||||
|     Ok(oklch.difference_relative(&other_oklch)) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn tint_scale( | ||||
|     basic_color: &str, | ||||
|     mixed_color: &str, | ||||
| ) -> Result<reversing::MixReversing, errors::ColorError> { | ||||
|     let basic_color = Srgb::from_str(basic_color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(basic_color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let mixed_color = Srgb::from_str(mixed_color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(mixed_color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     Ok(reversing::MixReversing::from_tint_rgb( | ||||
|         basic_color, | ||||
|         mixed_color, | ||||
|     )) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn shade_scale( | ||||
|     basic_color: &str, | ||||
|     mixed_color: &str, | ||||
| ) -> Result<reversing::MixReversing, errors::ColorError> { | ||||
|     let basic_color = Srgb::from_str(basic_color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(basic_color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let mixed_color = Srgb::from_str(mixed_color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(mixed_color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     Ok(reversing::MixReversing::from_shade_rgb( | ||||
|         basic_color, | ||||
|         mixed_color, | ||||
|     )) | ||||
| } | ||||
|   | ||||
							
								
								
									
										87
									
								
								color-module/src/series.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								color-module/src/series.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| use std::{str::FromStr, sync::Arc}; | ||||
|  | ||||
| use palette::{ | ||||
|     cam16::{Cam16Jch, Parameters}, | ||||
|     Darken, FromColor, IntoColor, Lighten, Oklch, Srgb, | ||||
| }; | ||||
| use wasm_bindgen::prelude::wasm_bindgen; | ||||
|  | ||||
| use crate::errors; | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn series( | ||||
|     color: &str, | ||||
|     expand_amount: i16, | ||||
|     step: f32, | ||||
| ) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Arc::new(Oklch::from_color(origin_color.clone())); | ||||
|  | ||||
|     let mut color_series = Vec::new(); | ||||
|     for s in (1..=expand_amount).rev() { | ||||
|         let darkened_color = Arc::clone(&oklch).darken(s as f32 * step); | ||||
|         let srgb = Srgb::from_color(darkened_color); | ||||
|         color_series.push(format!("{:x}", srgb.into_format::<u8>())); | ||||
|     } | ||||
|     color_series.push(format!("{:x}", origin_color.into_format::<u8>())); | ||||
|     for s in 1..=expand_amount { | ||||
|         let lightened_color = Arc::clone(&oklch).lighten(s as f32 * step); | ||||
|         let srgb = Srgb::from_color(lightened_color); | ||||
|         color_series.push(format!("{:x}", srgb.into_format::<u8>())); | ||||
|     } | ||||
|     Ok(color_series) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn tonal_lighten_series( | ||||
|     color: &str, | ||||
|     expand_amount: i16, | ||||
|     step: f32, | ||||
| ) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let hct = Cam16Jch::from_xyz( | ||||
|         origin_color.into_color(), | ||||
|         Parameters::default_static_wp(40.0), | ||||
|     ); | ||||
|  | ||||
|     let mut color_series = Vec::new(); | ||||
|     let mut lightness = hct.lightness; | ||||
|     for _ in 1..=expand_amount { | ||||
|         lightness += (100.0 - lightness) * step; | ||||
|         let lightened_color = Cam16Jch::new(lightness, hct.chroma, hct.hue); | ||||
|         let srgb = Srgb::from_color(lightened_color.into_xyz(Parameters::default_static_wp(40.0))); | ||||
|         color_series.push(format!("{:x}", srgb.into_format::<u8>())); | ||||
|     } | ||||
|  | ||||
|     Ok(color_series) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn tonal_darken_series( | ||||
|     color: &str, | ||||
|     expand_amount: i16, | ||||
|     step: f32, | ||||
| ) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let hct = Cam16Jch::from_xyz( | ||||
|         origin_color.into_color(), | ||||
|         Parameters::default_static_wp(40.0), | ||||
|     ); | ||||
|  | ||||
|     let mut color_series = Vec::new(); | ||||
|     let mut lightness = hct.lightness; | ||||
|     for _ in 1..=expand_amount { | ||||
|         lightness *= 1.0 - step; | ||||
|         let darkened_color = Cam16Jch::new(lightness, hct.chroma, hct.hue); | ||||
|         let srgb = Srgb::from_color(darkened_color.into_xyz(Parameters::default_static_wp(40.0))); | ||||
|         color_series.push(format!("{:x}", srgb.into_format::<u8>())); | ||||
|     } | ||||
|  | ||||
|     Ok(color_series.into_iter().rev().collect()) | ||||
| } | ||||
							
								
								
									
										108
									
								
								color-module/src/theory.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								color-module/src/theory.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| use std::str::FromStr; | ||||
|  | ||||
| use palette::{ | ||||
|     color_theory::{Analogous, Complementary, SplitComplementary, Tetradic, Triadic}, | ||||
|     FromColor, Oklch, ShiftHue, Srgb, | ||||
| }; | ||||
| use wasm_bindgen::prelude::wasm_bindgen; | ||||
|  | ||||
| use crate::errors; | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn shift_hue(color: &str, degree: f32) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let shifted_color = oklch.shift_hue(degree); | ||||
|     let srgb = Srgb::from_color(shifted_color); | ||||
|     Ok(format!("{:x}", srgb.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn analogous_30(color: &str) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let (color_n30, color_p30) = oklch.analogous(); | ||||
|     let srgb_n30 = Srgb::from_color(color_n30); | ||||
|     let srgb_p30 = Srgb::from_color(color_p30); | ||||
|     Ok(vec![ | ||||
|         format!("{:x}", srgb_n30.into_format::<u8>()), | ||||
|         format!("{:x}", srgb_p30.into_format::<u8>()), | ||||
|     ]) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn analogous_60(color: &str) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let (color_n60, color_p60) = oklch.analogous_secondary(); | ||||
|     let srgb_n60 = Srgb::from_color(color_n60); | ||||
|     let srgb_p60 = Srgb::from_color(color_p60); | ||||
|     Ok(vec![ | ||||
|         format!("{:x}", srgb_n60.into_format::<u8>()), | ||||
|         format!("{:x}", srgb_p60.into_format::<u8>()), | ||||
|     ]) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn complementary(color: &str) -> Result<String, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let complementary_color = oklch.complementary(); | ||||
|     let srgb = Srgb::from_color(complementary_color); | ||||
|     Ok(format!("{:x}", srgb.into_format::<u8>())) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn split_complementary(color: &str) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let (color_p150, color_p210) = oklch.split_complementary(); | ||||
|     let srgb_p150 = Srgb::from_color(color_p150); | ||||
|     let srgb_p210 = Srgb::from_color(color_p210); | ||||
|     Ok(vec![ | ||||
|         format!("{:x}", srgb_p150.into_format::<u8>()), | ||||
|         format!("{:x}", srgb_p210.into_format::<u8>()), | ||||
|     ]) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn tetradic(color: &str) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let (color_p90, color_p180, color_p270) = oklch.tetradic(); | ||||
|     let srgb_p90 = Srgb::from_color(color_p90); | ||||
|     let srgb_p180 = Srgb::from_color(color_p180); | ||||
|     let srgb_p270 = Srgb::from_color(color_p270); | ||||
|     Ok(vec![ | ||||
|         format!("{:x}", srgb_p90.into_format::<u8>()), | ||||
|         format!("{:x}", srgb_p180.into_format::<u8>()), | ||||
|         format!("{:x}", srgb_p270.into_format::<u8>()), | ||||
|     ]) | ||||
| } | ||||
|  | ||||
| #[wasm_bindgen] | ||||
| pub fn triadic(color: &str) -> Result<Vec<String>, errors::ColorError> { | ||||
|     let origin_color = Srgb::from_str(color) | ||||
|         .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? | ||||
|         .into_format::<f32>(); | ||||
|     let oklch = Oklch::from_color(origin_color); | ||||
|     let (color_p120, color_p240) = oklch.triadic(); | ||||
|     let srgb_p120 = Srgb::from_color(color_p120); | ||||
|     let srgb_p240 = Srgb::from_color(color_p240); | ||||
|     Ok(vec![ | ||||
|         format!("{:x}", srgb_p120.into_format::<u8>()), | ||||
|         format!("{:x}", srgb_p240.into_format::<u8>()), | ||||
|     ]) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user