use std;
use error::{RasterError, RasterResult};
#[derive(Debug, Clone)]
pub struct Color {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
impl<'a> Color {
pub fn black() -> Color {
Color {
r: 0,
g: 0,
b: 0,
a: 255,
}
}
pub fn blue() -> Color {
Color {
r: 0,
g: 0,
b: 255,
a: 255,
}
}
pub fn green() -> Color {
Color {
r: 0,
g: 255,
b: 0,
a: 255,
}
}
pub fn hex(hex: &str) -> RasterResult<Color> {
if hex.len() == 9 && hex.starts_with('#') { Ok(Color {
r: try!(_hex_dec(&hex[1..3])),
g: try!(_hex_dec(&hex[3..5])),
b: try!(_hex_dec(&hex[5..7])),
a: try!(_hex_dec(&hex[7..9])),
})
} else if hex.len() == 7 && hex.starts_with('#') { Ok(Color {
r: try!(_hex_dec(&hex[1..3])),
g: try!(_hex_dec(&hex[3..5])),
b: try!(_hex_dec(&hex[5..7])),
a: 255,
})
} else {
Err(RasterError::InvalidHex)
}
}
pub fn red() -> Color {
Color {
r: 255,
g: 0,
b: 0,
a: 255,
}
}
pub fn rgb(r:u8, g:u8, b:u8) -> Color {
Color {
r: r,
g: g,
b: b,
a: 255,
}
}
pub fn rgba(r:u8, g:u8, b:u8, a:u8) -> Color {
Color {
r: r,
g: g,
b: b,
a: a,
}
}
pub fn to_hsv(r: u8, g: u8, b: u8) -> (u16, f32, f32) {
let r = r as f32 / 255.0;
let g = g as f32 / 255.0;
let b = b as f32 / 255.0;
let min = rgb_min(r, g, b);
let max = rgb_max(r, g, b);
let chroma = max - min;
let h = {
let mut h = 0.0;
if chroma != 0.0 {
if (max - r).abs() < std::f32::EPSILON {
h = 60.0 * ((g - b) / chroma);
if h < 0.0 {
h += 360.0;
}
} else if (max - g).abs() < std::f32::EPSILON {
h = 60.0 * (((b - r) / chroma) + 2.0);
} else if (max - b).abs() < std::f32::EPSILON {
h = 60.0 * (((r - g) / chroma) + 4.0);
}
}
if h > 359.0 {
h = 360.0 - h; }
h
};
let v = max;
let s = if v != 0.0 {
chroma / v
} else {
0.0
};
( h.round() as u16, s * 100.0, v * 100.0 )
}
pub fn to_rgb(h:u16, s: f32, v: f32) -> (u8, u8, u8) {
let h = h as f32 / 60.0;
let s = s as f32 / 100.0; let v = v as f32 / 100.0;
let chroma = v * s;
let x = chroma * ( 1.0 - ( (h % 2.0) - 1.0 ).abs() );
let mut r = 0.0;
let mut g = 0.0;
let mut b = 0.0;
if h >= 0.0 {
if h < 1.0 {
r = chroma;
g = x;
b = 0.0;
} else if h < 2.0 {
r = x;
g = chroma;
b = 0.0;
} else if h < 3.0 {
r = 0.0;
g = chroma;
b = x;
} else if h < 4.0 {
r = 0.0;
g = x;
b = chroma;
} else if h < 5.0 {
r = x;
g = 0.0;
b = chroma;
} else if h < 6.0 {
r = chroma;
g = 0.0;
b = x;
}
}
let m = v - chroma;
r += m;
g += m;
b += m;
( (r * 255.0).round() as u8, (g * 255.0).round() as u8, (b * 255.0).round() as u8)
}
pub fn white() -> Color {
Color {
r: 255,
g: 255,
b: 255,
a: 255,
}
}
}
fn _hex_dec(hex_string: &str) -> RasterResult<u8> {
u8::from_str_radix(hex_string, 16)
.map(|o| o as u8)
.map_err(RasterError::HexParse)
}
fn rgb_min(r: f32, g: f32, b: f32) -> f32 {
let min = if g < r {
g
} else {
r
};
if b < min {
b
} else {
min
}
}
fn rgb_max(r: f32, g: f32, b: f32) -> f32 {
let max = if g > r {
g
} else {
r
};
if b > max {
b
} else {
max
}
}