pixel 0.1.3

Prototype! Pixel manipulation library (blend and convert colors)
Documentation
use super::rgb::RGB;

use std::cmp::PartialOrd;
use std::f32::NAN;

pub fn min<T: PartialOrd>(lhs: T, rhs: T) -> T { if lhs < rhs { lhs } else { rhs } }
pub fn max<T: PartialOrd>(lhs: T, rhs: T) -> T { if lhs < rhs { rhs } else { lhs } }

macro_rules! min {
    ($x:expr, $y:expr) => ( min($x, $y) );
    ($x:expr, $($y:expr),*) => ( min($x, min!($($y),*)) );
}
macro_rules! max {
    ($x:expr, $y:expr) => ( max($x, $y) );
    ($x:expr, $($y:expr),*) => ( max($x, max!($($y),*)) );
}

pub fn pack_chanel_value(value: f32, power: f32, limit: usize) -> u64 { (value * limit as f32 / power).round() as u64 }
pub fn unpack_chanel_value(value: u64, limit: usize, power: f32) -> f32 { value as f32 * power / limit as f32 }

pub fn get_hue(rgb: RGB) -> f32 {
    let RGB{red, green, blue} = rgb;
    let max = max!(red, green, blue);
    let min = min!(red, green, blue);
    let color = max - min;
    if color == 0.0 { return NAN; }
    let hue = if max == red {
        ((green - blue) / color)
    } else if max == green {
        ((blue - red) / color) + 2.0
    } else {
        ((red - green) / color) + 4.0
    };
    (hue % 6.0) * 60.0
}

pub fn get_hsv_saturation(rgb: RGB) -> f32 {
    let RGB{red, green, blue} = rgb;
    let max = max!(red, green, blue);
    let min = min!(red, green, blue);
    let color = max - min;
    color / get_value(rgb)
}

pub fn get_hsl_saturation(rgb: RGB) -> f32 {
    let RGB{red, green, blue} = rgb;
    let max = max!(red, green, blue);
    let min = min!(red, green, blue);
    let color = max - min;
    color / (1.0 - (2.0 * get_lightness(rgb) - 1.0).abs())
}

pub fn get_hsi_saturation(rgb: RGB) -> f32 {
    let RGB{red, green, blue} = rgb;
    let min = min!(red, green, blue);
    1.0 - (min / get_intensity(rgb))
}

pub fn get_value(rgb: RGB) -> f32 { let RGB{red, green, blue} = rgb; max!(red, green, blue) }

pub fn get_lightness(rgb: RGB) -> f32 {
    let RGB{red, green, blue} = rgb;
    let max = max!(red, green, blue);
    let min = min!(red, green, blue);
    (max + min) / 2.0
}

pub fn get_intensity(rgb: RGB) -> f32 {
    let RGB{red, green, blue} = rgb;
    (red + green + blue) / 3.0
}

pub fn rgb_from_hcm(hue: f32, color: f32, min: f32) -> RGB {
    let (r1, g1, b1) = if hue.is_nan() {
        (0.0, 0.0, 0.0)
    } else {
        assert!(0.0 <= hue && hue < 360.0);
        let hue = (hue - (hue / 360.0).floor() * 360.0) / 60.0;
        let x = color * (1.0 - ((hue % 2.0) - 1.0).abs());
        if hue >= 5.0 {
            (color, 0.0, x)
        } else if hue >= 4.0 {
            (x, 0.0, color)
        } else if hue >= 3.0 {
            (0.0, x, color)
        } else if hue >= 2.0 {
            (0.0, color, x)
        } else if hue >= 1.0 {
            (x, color, 0.0)
        } else if hue >= 0.0 {
            (color, x, 0.0)
        } else {
            unreachable!()
        }
    };
    return RGB::new(r1 + min, g1 + min, b1 + min);
}