feat: hsv color format implemented with rgb parsing
This commit is contained in:
69
colorizer/src/color/hsv.rs
Normal file
69
colorizer/src/color/hsv.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use crate::color::{ColorHue, HSV, Percentage, RGB};
|
||||
|
||||
impl HSV {
|
||||
pub fn new(h: u16, s: u8, v: u8) -> Self {
|
||||
Self(
|
||||
ColorHue::new(h as i16),
|
||||
Percentage::new(s as i16),
|
||||
Percentage::new(v as i16),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for HSV {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "hsv({}, {}%, {}%)", self.0, self.1, self.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for HSV {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0 == other.0 && self.1 == other.1 && self.2 == other.2
|
||||
}
|
||||
|
||||
fn ne(&self, other: &Self) -> bool {
|
||||
self.0 != other.0 || self.1 != other.1 || self.2 != other.2
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RGB> for HSV {
|
||||
fn from(color: RGB) -> Self {
|
||||
let r = color.0.to_f32() / 255.0;
|
||||
let g = color.1.to_f32() / 255.0;
|
||||
let b = color.2.to_f32() / 255.0;
|
||||
|
||||
let min: f32 = r.min(g.min(b));
|
||||
let max: f32 = r.max(g.max(b));
|
||||
|
||||
let v = max;
|
||||
|
||||
if min == max {
|
||||
return Self::new(0, 0, v as u8);
|
||||
}
|
||||
|
||||
let s = (max - min) / max;
|
||||
let dif = max - min;
|
||||
let rc = (max - r) / dif;
|
||||
let gc = (max - g) / dif;
|
||||
let bc = (max - b) / dif;
|
||||
|
||||
let mut h: f32;
|
||||
if r == max {
|
||||
h = bc - gc;
|
||||
} else if g == max {
|
||||
h = 2.0 + rc - bc;
|
||||
} else {
|
||||
h = 4.0 + gc - rc;
|
||||
}
|
||||
|
||||
h = (h / 6.0).rem_euclid(1.0);
|
||||
|
||||
Self::new(
|
||||
(h * 360.0).round() as u16,
|
||||
(s * 100.0).round() as u8,
|
||||
(v * 100.0).round() as u8,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,10 @@
|
||||
mod test;
|
||||
|
||||
pub mod hsl;
|
||||
pub mod hsv;
|
||||
pub mod rgb;
|
||||
|
||||
use std::fmt::{UpperHex, write};
|
||||
use std::fmt::UpperHex;
|
||||
|
||||
use crate::core::ranged::RangedInt;
|
||||
|
||||
@@ -16,15 +17,12 @@ pub type Percentage = RangedInt<0, 100>;
|
||||
pub struct RGB(ColorIntensity, ColorIntensity, ColorIntensity);
|
||||
#[derive(Debug)]
|
||||
pub struct HSL(ColorHue, Percentage, Percentage);
|
||||
// pub struct HSV(ColorHue, Percentage, Percentage);
|
||||
#[derive(Debug)]
|
||||
pub struct HSV(ColorHue, Percentage, Percentage);
|
||||
#[derive(Debug)]
|
||||
pub struct Color(RGB);
|
||||
|
||||
impl Color {
|
||||
pub fn format(&self) -> String {
|
||||
format!("{:?}", self.0)
|
||||
}
|
||||
}
|
||||
impl Color {}
|
||||
|
||||
impl UpperHex for Color {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
@@ -53,3 +51,9 @@ impl From<HSL> for Color {
|
||||
Color(RGB::from(color))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HSV> for Color {
|
||||
fn from(color: HSV) -> Self {
|
||||
Color(RGB::from(color))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::fmt::UpperHex;
|
||||
use std::fmt::{Display, UpperHex};
|
||||
|
||||
use crate::{
|
||||
color::{ColorIntensity, HSL, RGB},
|
||||
color::{ColorIntensity, HSL, HSV, RGB},
|
||||
core::ranged::BaseNumber,
|
||||
};
|
||||
|
||||
@@ -25,6 +25,12 @@ impl PartialEq for RGB {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for RGB {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "rgb({}, {}, {})", self.0, self.1, self.2)
|
||||
}
|
||||
}
|
||||
|
||||
impl UpperHex for RGB {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:0>2X}{:0>2X}{:0>2X}", self.0, self.1, self.2)
|
||||
@@ -86,3 +92,66 @@ impl From<HSL> for RGB {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HSV> for RGB {
|
||||
fn from(color: HSV) -> Self {
|
||||
let h = color.0.to_f32() / 360.0;
|
||||
let s = color.1.to_f32() / 100.0;
|
||||
let v = color.2.to_f32() / 100.0;
|
||||
|
||||
if s == 0.0 {
|
||||
let grey = (v * 255.0) as u8;
|
||||
return Self::new(grey, grey, grey);
|
||||
}
|
||||
|
||||
let i = (h * 6.0) as u8;
|
||||
|
||||
let f = (h * 6.0) - i as f32;
|
||||
let p = v * (1.0 - s);
|
||||
let q = v * (1.0 - s * f);
|
||||
let t = v * (1.0 - s * (1.0 - f));
|
||||
let i = i % 6;
|
||||
|
||||
if i == 0 {
|
||||
return Self::new(
|
||||
(v * 255.0).round() as u8,
|
||||
(t * 255.0).round() as u8,
|
||||
(p * 255.0).round() as u8,
|
||||
);
|
||||
}
|
||||
if i == 1 {
|
||||
return Self::new(
|
||||
(q * 255.0).round() as u8,
|
||||
(v * 255.0).round() as u8,
|
||||
(p * 255.0).round() as u8,
|
||||
);
|
||||
}
|
||||
if i == 2 {
|
||||
return Self::new(
|
||||
(p * 255.0).round() as u8,
|
||||
(v * 255.0).round() as u8,
|
||||
(t * 255.0).round() as u8,
|
||||
);
|
||||
}
|
||||
if i == 3 {
|
||||
return Self::new(
|
||||
(p * 255.0).round() as u8,
|
||||
(q * 255.0).round() as u8,
|
||||
(v * 255.0).round() as u8,
|
||||
);
|
||||
}
|
||||
if i == 4 {
|
||||
return Self::new(
|
||||
(t * 255.0).round() as u8,
|
||||
(p * 255.0).round() as u8,
|
||||
(v * 255.0).round() as u8,
|
||||
);
|
||||
}
|
||||
|
||||
return Self::new(
|
||||
(v * 255.0).round() as u8,
|
||||
(p * 255.0).round() as u8,
|
||||
(q * 255.0).round() as u8,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use std::fmt::format;
|
||||
use crate::color::{Color, HSL, HSV, RGB};
|
||||
|
||||
use crate::color::{Color, HSL, RGB};
|
||||
#[test]
|
||||
fn test_color_initialization() {
|
||||
let red_hsl = Color::from(HSL::new(0, 100, 50));
|
||||
let red_rgb = Color::from(RGB::new(255, 0, 0));
|
||||
assert_eq!(red_hsl, red_rgb);
|
||||
|
||||
let green_hsl = Color::from(HSL::new(120, 100, 50));
|
||||
let green_rgb = Color::from(RGB::new(0, 255, 0));
|
||||
assert_eq!(green_hsl, green_rgb);
|
||||
|
||||
let blue_hsl = Color::from(HSL::new(240, 100, 50));
|
||||
let blue_rgb = Color::from(RGB::new(0, 0, 255));
|
||||
assert_eq!(blue_hsl, blue_rgb);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conversion() {
|
||||
@@ -117,17 +130,36 @@ pub mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_color_initialization() {
|
||||
let red_hsl = Color::from(HSL::new(0, 100, 50));
|
||||
let red_rgb = Color::from(RGB::new(255, 0, 0));
|
||||
assert_eq!(red_hsl, red_rgb);
|
||||
fn test_hsv_from_rgb() {
|
||||
// Base colors
|
||||
let color = RGB::new(255, 0, 0);
|
||||
assert_eq!(HSV::from(color), HSV::new(0, 100, 100));
|
||||
let color = RGB::new(0, 255, 0);
|
||||
assert_eq!(HSV::from(color), HSV::new(120, 100, 100));
|
||||
let color = RGB::new(0, 0, 255);
|
||||
assert_eq!(HSV::from(color), HSV::new(240, 100, 100));
|
||||
|
||||
let green_hsl = Color::from(HSL::new(120, 100, 50));
|
||||
let green_rgb = Color::from(RGB::new(0, 255, 0));
|
||||
assert_eq!(green_hsl, green_rgb);
|
||||
// Complex colors
|
||||
let color = RGB::new(20, 240, 100);
|
||||
assert_eq!(HSV::from(color), HSV::new(142, 92, 94));
|
||||
let color = RGB::new(220, 10, 50);
|
||||
assert_eq!(HSV::from(color), HSV::new(349, 95, 86));
|
||||
}
|
||||
|
||||
let blue_hsl = Color::from(HSL::new(240, 100, 50));
|
||||
let blue_rgb = Color::from(RGB::new(0, 0, 255));
|
||||
assert_eq!(blue_hsl, blue_rgb);
|
||||
#[test]
|
||||
fn test_rgb_from_hsv() {
|
||||
// Base colors
|
||||
let color = HSV::new(0, 100, 100);
|
||||
assert_eq!(RGB::from(color), RGB::new(255, 0, 0));
|
||||
let color = HSV::new(120, 100, 100);
|
||||
assert_eq!(RGB::from(color), RGB::new(0, 255, 0));
|
||||
let color = HSV::new(240, 100, 100);
|
||||
assert_eq!(RGB::from(color), RGB::new(0, 0, 255));
|
||||
|
||||
// Complex colors
|
||||
let color = HSV::new(349, 95, 86);
|
||||
assert_eq!(RGB::from(color), RGB::new(219, 11, 49));
|
||||
let color = HSV::new(142, 92, 94);
|
||||
assert_eq!(RGB::from(color), RGB::new(19, 240, 100));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use clipboard::ClipboardContext;
|
||||
use clipboard::ClipboardProvider;
|
||||
|
||||
use crate::color::Color;
|
||||
use crate::color::HSL;
|
||||
use crate::color::HSV;
|
||||
use crate::color::RGB;
|
||||
|
||||
mod color;
|
||||
@@ -18,8 +17,7 @@ fn main() {
|
||||
println!("Hello, world!");
|
||||
example();
|
||||
|
||||
let hsl_color = Color::from(HSL::new(0, 100, 50));
|
||||
// let rgb_color = Color::from(HSL::new(193, 67, 28));
|
||||
println!("RGB Color: {:X}", hsl_color);
|
||||
// println!("RGB Color: {}", rgb_color.format());
|
||||
let color = RGB::new(220, 10, 50);
|
||||
let hsv_color = HSV::from(RGB::new(220, 10, 50));
|
||||
println!("RGB color: {}, HSV Color: {}", color, hsv_color);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user