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;
|
mod test;
|
||||||
|
|
||||||
pub mod hsl;
|
pub mod hsl;
|
||||||
|
pub mod hsv;
|
||||||
pub mod rgb;
|
pub mod rgb;
|
||||||
|
|
||||||
use std::fmt::{UpperHex, write};
|
use std::fmt::UpperHex;
|
||||||
|
|
||||||
use crate::core::ranged::RangedInt;
|
use crate::core::ranged::RangedInt;
|
||||||
|
|
||||||
@@ -16,15 +17,12 @@ pub type Percentage = RangedInt<0, 100>;
|
|||||||
pub struct RGB(ColorIntensity, ColorIntensity, ColorIntensity);
|
pub struct RGB(ColorIntensity, ColorIntensity, ColorIntensity);
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct HSL(ColorHue, Percentage, Percentage);
|
pub struct HSL(ColorHue, Percentage, Percentage);
|
||||||
// pub struct HSV(ColorHue, Percentage, Percentage);
|
#[derive(Debug)]
|
||||||
|
pub struct HSV(ColorHue, Percentage, Percentage);
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Color(RGB);
|
pub struct Color(RGB);
|
||||||
|
|
||||||
impl Color {
|
impl Color {}
|
||||||
pub fn format(&self) -> String {
|
|
||||||
format!("{:?}", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UpperHex for Color {
|
impl UpperHex for Color {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
@@ -53,3 +51,9 @@ impl From<HSL> for Color {
|
|||||||
Color(RGB::from(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::{
|
use crate::{
|
||||||
color::{ColorIntensity, HSL, RGB},
|
color::{ColorIntensity, HSL, HSV, RGB},
|
||||||
core::ranged::BaseNumber,
|
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 {
|
impl UpperHex for RGB {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
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)
|
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)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
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]
|
#[test]
|
||||||
fn test_conversion() {
|
fn test_conversion() {
|
||||||
@@ -117,17 +130,36 @@ pub mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_color_initialization() {
|
fn test_hsv_from_rgb() {
|
||||||
let red_hsl = Color::from(HSL::new(0, 100, 50));
|
// Base colors
|
||||||
let red_rgb = Color::from(RGB::new(255, 0, 0));
|
let color = RGB::new(255, 0, 0);
|
||||||
assert_eq!(red_hsl, red_rgb);
|
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));
|
// Complex colors
|
||||||
let green_rgb = Color::from(RGB::new(0, 255, 0));
|
let color = RGB::new(20, 240, 100);
|
||||||
assert_eq!(green_hsl, green_rgb);
|
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));
|
#[test]
|
||||||
let blue_rgb = Color::from(RGB::new(0, 0, 255));
|
fn test_rgb_from_hsv() {
|
||||||
assert_eq!(blue_hsl, blue_rgb);
|
// 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::ClipboardContext;
|
||||||
use clipboard::ClipboardProvider;
|
use clipboard::ClipboardProvider;
|
||||||
|
|
||||||
use crate::color::Color;
|
use crate::color::HSV;
|
||||||
use crate::color::HSL;
|
|
||||||
use crate::color::RGB;
|
use crate::color::RGB;
|
||||||
|
|
||||||
mod color;
|
mod color;
|
||||||
@@ -18,8 +17,7 @@ fn main() {
|
|||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
example();
|
example();
|
||||||
|
|
||||||
let hsl_color = Color::from(HSL::new(0, 100, 50));
|
let color = RGB::new(220, 10, 50);
|
||||||
// let rgb_color = Color::from(HSL::new(193, 67, 28));
|
let hsv_color = HSV::from(RGB::new(220, 10, 50));
|
||||||
println!("RGB Color: {:X}", hsl_color);
|
println!("RGB color: {}, HSV Color: {}", color, hsv_color);
|
||||||
// println!("RGB Color: {}", rgb_color.format());
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user