Fix color channel conversions
This commit is contained in:
parent
a5d4fc1ed4
commit
2ca90cb750
6 changed files with 265 additions and 152 deletions
|
@ -14,7 +14,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
/// A color channel
|
/// A color channel
|
||||||
pub trait Channel: Num {
|
pub trait Channel: Num + ToChannel{
|
||||||
/// Convert a channel to the enclosing type
|
/// Convert a channel to the enclosing type
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
@ -23,98 +23,166 @@ pub trait Channel: Num {
|
||||||
/// let chan: f32 = Channel::from(0xFFFFu16);
|
/// let chan: f32 = Channel::from(0xFFFFu16);
|
||||||
/// assert chan == 1.0f32;
|
/// assert chan == 1.0f32;
|
||||||
/// ~~~
|
/// ~~~
|
||||||
pub fn from<T:Channel>(val: T) -> Self;
|
pub fn from<T: ToChannel>(val: T) -> Self;
|
||||||
|
|
||||||
pub fn to_channel_u8(&self) -> u8;
|
|
||||||
pub fn to_channel_u16(&self) -> u16;
|
|
||||||
pub fn to_channel_u32(&self) -> u32;
|
|
||||||
pub fn to_channel_u64(&self) -> u64;
|
|
||||||
pub fn to_channel_f32(&self) -> f32;
|
|
||||||
pub fn to_channel_f64(&self) -> f64;
|
|
||||||
pub fn to_channel_float(&self) -> float;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Channel for u8 {
|
impl Channel for u8 {
|
||||||
#[inline] pub fn from<T:Channel>(val: T) -> u8 { val.to_channel_u8() }
|
#[inline] pub fn from<T: ToChannel>(val: T) -> u8 { val.to_channel_u8() }
|
||||||
|
|
||||||
#[inline] pub fn to_channel_u8(&self) -> u8 { (*self) }
|
|
||||||
#[inline] pub fn to_channel_u16(&self) -> u16 { (*self as u16 << 8) | (*self) as u16 }
|
|
||||||
#[inline] pub fn to_channel_u32(&self) -> u32 { (self.to_channel_u16() as u32 << 16) | self.to_channel_u16() as u32 }
|
|
||||||
#[inline] pub fn to_channel_u64(&self) -> u64 { (self.to_channel_u32() as u64 << 32) | self.to_channel_u32() as u64 }
|
|
||||||
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self as f32) / (0xFF as f32) }
|
|
||||||
#[inline] pub fn to_channel_f64(&self) -> f64 { (*self as f64) / (0xFF as f64) }
|
|
||||||
#[inline] pub fn to_channel_float(&self) -> float { (*self as float) / (0xFF as float) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Channel for u16 {
|
impl Channel for u16 {
|
||||||
#[inline] pub fn from<T:Channel>(val: T) -> u16 { val.to_channel_u16() }
|
#[inline] pub fn from<T: ToChannel>(val: T) -> u16 { val.to_channel_u16() }
|
||||||
|
|
||||||
#[inline] pub fn to_channel_u8(&self) -> u8 { (*self >> 8) as u8 } // this is the equivalent of `self/256`. Some folks prefer to do `self/257`
|
|
||||||
#[inline] pub fn to_channel_u16(&self) -> u16 { (*self) }
|
|
||||||
#[inline] pub fn to_channel_u32(&self) -> u32 { (*self as u32 << 16) | (*self) as u32 }
|
|
||||||
#[inline] pub fn to_channel_u64(&self) -> u64 { (self.to_channel_u32() as u64 << 32) | self.to_channel_u32() as u64 }
|
|
||||||
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self) / 0xFFFF as f32 }
|
|
||||||
#[inline] pub fn to_channel_f64(&self) -> f64 { (*self) / 0xFFFF as f64 }
|
|
||||||
#[inline] pub fn to_channel_float(&self) -> float { (*self) / 0xFFFF as float }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Channel for u32 {
|
impl Channel for u32 {
|
||||||
#[inline] pub fn from<T:Channel>(val: T) -> u32 { val.to_channel_u32() }
|
#[inline] pub fn from<T: ToChannel>(val: T) -> u32 { val.to_channel_u32() }
|
||||||
|
|
||||||
#[inline] pub fn to_channel_u8(&self) -> u8 { (*self >> 24) as u8 }
|
|
||||||
#[inline] pub fn to_channel_u16(&self) -> u16 { (*self >> 16) as u16 }
|
|
||||||
#[inline] pub fn to_channel_u32(&self) -> u32 { (*self) }
|
|
||||||
#[inline] pub fn to_channel_u64(&self) -> u64 { (*self as u64 << 32) | (*self) as u64 }
|
|
||||||
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self) / 0xFFFF_FFFF as f32 }
|
|
||||||
#[inline] pub fn to_channel_f64(&self) -> f64 { (*self) / 0xFFFF_FFFF as f64 }
|
|
||||||
#[inline] pub fn to_channel_float(&self) -> float { (*self) / 0xFFFF_FFFF as float }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Channel for u64 {
|
impl Channel for u64 {
|
||||||
#[inline] pub fn from<T:Channel>(val: T) -> u64 { val.to_channel_u64() }
|
#[inline] pub fn from<T: ToChannel>(val: T) -> u64 { val.to_channel_u64() }
|
||||||
|
|
||||||
#[inline] pub fn to_channel_u8(&self) -> u8 { (*self >> 56) as u8 }
|
|
||||||
#[inline] pub fn to_channel_u16(&self) -> u16 { (*self >> 48) as u16 }
|
|
||||||
#[inline] pub fn to_channel_u32(&self) -> u32 { (*self >> 32) as u32 }
|
|
||||||
#[inline] pub fn to_channel_u64(&self) -> u64 { (*self) }
|
|
||||||
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self) / 0xFFFF_FFFF_FFFF_FFFF_u64 as f32 }
|
|
||||||
#[inline] pub fn to_channel_f64(&self) -> f64 { (*self) / 0xFFFF_FFFF_FFFF_FFFF_u64 as f64 }
|
|
||||||
#[inline] pub fn to_channel_float(&self) -> float { (*self) / 0xFFFF_FFFF_FFFF_FFFF_u64 as float }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Channel for f32 {
|
impl Channel for f32 {
|
||||||
#[inline] pub fn from<T:Channel>(val: T) -> f32 { val.to_channel_f32() }
|
#[inline] pub fn from<T: ToChannel>(val: T) -> f32 { val.to_channel_f32() }
|
||||||
|
|
||||||
|
|
||||||
#[inline] pub fn to_channel_u8(&self) -> u8 { (*self) * (0xFF_u8 as f32) as u8 }
|
|
||||||
#[inline] pub fn to_channel_u16(&self) -> u16 { (*self) * (0xFFFF_u16 as f32) as u16 }
|
|
||||||
#[inline] pub fn to_channel_u32(&self) -> u32 { fail!(~"to_channel_u32 not yet implemented for f32") }
|
|
||||||
#[inline] pub fn to_channel_u64(&self) -> u64 { fail!(~"to_channel_u64 not yet implemented for f32") }
|
|
||||||
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self) }
|
|
||||||
#[inline] pub fn to_channel_f64(&self) -> f64 { (*self) as f64 }
|
|
||||||
#[inline] pub fn to_channel_float(&self) -> float { (*self) as float }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Channel for f64 {
|
impl Channel for f64 {
|
||||||
#[inline] pub fn from<T:Channel>(val: T) -> f64 { val.to_channel_f64() }
|
#[inline] pub fn from<T: ToChannel>(val: T) -> f64 { val.to_channel_f64() }
|
||||||
|
|
||||||
#[inline] pub fn to_channel_u8(&self) -> u8 { (*self) * (0xFF_u8 as f64) as u8 }
|
|
||||||
#[inline] pub fn to_channel_u16(&self) -> u16 { (*self) * (0xFFFF_u16 as f64) as u16 }
|
|
||||||
#[inline] pub fn to_channel_u32(&self) -> u32 { fail!(~"to_channel_u32 not yet implemented for f64") }
|
|
||||||
#[inline] pub fn to_channel_u64(&self) -> u64 { fail!(~"to_channel_u64 not yet implemented for f64") }
|
|
||||||
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self) as f32 }
|
|
||||||
#[inline] pub fn to_channel_f64(&self) -> f64 { (*self) }
|
|
||||||
#[inline] pub fn to_channel_float(&self) -> float { (*self) as float }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Channel for float {
|
pub trait ToChannel: ToIntChannel + ToFloatChannel {}
|
||||||
#[inline] pub fn from<T:Channel>(val: T) -> float { val.to_channel_float() }
|
|
||||||
|
|
||||||
#[inline] pub fn to_channel_u8(&self) -> u8 { (*self) * (0xFF_u8 as float) as u8 }
|
impl ToChannel for u8 {}
|
||||||
#[inline] pub fn to_channel_u16(&self) -> u16 { (*self) * (0xFFFF_u16 as float) as u16 }
|
|
||||||
#[inline] pub fn to_channel_u32(&self) -> u32 { fail!(~"to_channel_u32 not yet implemented for float") }
|
impl ToChannel for u16 {}
|
||||||
#[inline] pub fn to_channel_u64(&self) -> u64 { fail!(~"to_channel_u64 not yet implemented for float") }
|
|
||||||
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self) as f32 }
|
impl ToChannel for u32 {}
|
||||||
#[inline] pub fn to_channel_f64(&self) -> f64 { (*self) as f64 }
|
|
||||||
#[inline] pub fn to_channel_float(&self) -> float { (*self) }
|
impl ToChannel for u64 {}
|
||||||
|
|
||||||
|
impl ToChannel for f32 {}
|
||||||
|
|
||||||
|
impl ToChannel for f64 {}
|
||||||
|
|
||||||
|
pub trait IntChannel: Int + Channel + ToIntChannel {
|
||||||
|
pub fn from<T:ToIntChannel>(val: T) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntChannel for u8 {
|
||||||
|
#[inline] pub fn from<T:ToIntChannel>(val: T) -> u8 { val.to_channel_u8() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntChannel for u16 {
|
||||||
|
#[inline] pub fn from<T:ToIntChannel>(val: T) -> u16 { val.to_channel_u16() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntChannel for u32 {
|
||||||
|
#[inline] pub fn from<T:ToIntChannel>(val: T) -> u32 { val.to_channel_u32() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntChannel for u64 {
|
||||||
|
#[inline] pub fn from<T:ToIntChannel>(val: T) -> u64 { val.to_channel_u64() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ToIntChannel {
|
||||||
|
pub fn to_channel_u8(&self) -> u8;
|
||||||
|
pub fn to_channel_u16(&self) -> u16;
|
||||||
|
pub fn to_channel_u32(&self) -> u32;
|
||||||
|
pub fn to_channel_u64(&self) -> u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIntChannel for u8 {
|
||||||
|
#[inline] pub fn to_channel_u8(&self) -> u8 { (*self) }
|
||||||
|
#[inline] pub fn to_channel_u16(&self) -> u16 { (*self as u16 << 8) | (*self) as u16 }
|
||||||
|
#[inline] pub fn to_channel_u32(&self) -> u32 { (self.to_channel_u16() as u32 << 16) | self.to_channel_u16() as u32 }
|
||||||
|
#[inline] pub fn to_channel_u64(&self) -> u64 { (self.to_channel_u32() as u64 << 32) | self.to_channel_u32() as u64 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIntChannel for u16 {
|
||||||
|
#[inline] pub fn to_channel_u8(&self) -> u8 { (*self >> 8) as u8 } // this is the equivalent of `self/256`. Some folks prefer to do `self/257`
|
||||||
|
#[inline] pub fn to_channel_u16(&self) -> u16 { (*self) }
|
||||||
|
#[inline] pub fn to_channel_u32(&self) -> u32 { (*self as u32 << 16) | (*self) as u32 }
|
||||||
|
#[inline] pub fn to_channel_u64(&self) -> u64 { (self.to_channel_u32() as u64 << 32) | self.to_channel_u32() as u64 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIntChannel for u32 {
|
||||||
|
#[inline] pub fn to_channel_u8(&self) -> u8 { (*self >> 24) as u8 }
|
||||||
|
#[inline] pub fn to_channel_u16(&self) -> u16 { (*self >> 16) as u16 }
|
||||||
|
#[inline] pub fn to_channel_u32(&self) -> u32 { (*self) }
|
||||||
|
#[inline] pub fn to_channel_u64(&self) -> u64 { (*self as u64 << 32) | (*self) as u64 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIntChannel for u64 {
|
||||||
|
#[inline] pub fn to_channel_u8(&self) -> u8 { (*self >> 56) as u8 }
|
||||||
|
#[inline] pub fn to_channel_u16(&self) -> u16 { (*self >> 48) as u16 }
|
||||||
|
#[inline] pub fn to_channel_u32(&self) -> u32 { (*self >> 32) as u32 }
|
||||||
|
#[inline] pub fn to_channel_u64(&self) -> u64 { (*self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIntChannel for f32 {
|
||||||
|
#[inline] pub fn to_channel_u8(&self) -> u8 { (*self) * (0xFF_u8 as f32) as u8 }
|
||||||
|
#[inline] pub fn to_channel_u16(&self) -> u16 { (*self) * (0xFFFF_u16 as f32) as u16 }
|
||||||
|
#[inline] pub fn to_channel_u32(&self) -> u32 { fail!(~"to_channel_u32 not yet implemented for f32") }
|
||||||
|
#[inline] pub fn to_channel_u64(&self) -> u64 { fail!(~"to_channel_u64 not yet implemented for f32") }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIntChannel for f64 {
|
||||||
|
#[inline] pub fn to_channel_u8(&self) -> u8 { (*self) * (0xFF_u8 as f64) as u8 }
|
||||||
|
#[inline] pub fn to_channel_u16(&self) -> u16 { (*self) * (0xFFFF_u16 as f64) as u16 }
|
||||||
|
#[inline] pub fn to_channel_u32(&self) -> u32 { fail!(~"to_channel_u32 not yet implemented for f64") }
|
||||||
|
#[inline] pub fn to_channel_u64(&self) -> u64 { fail!(~"to_channel_u64 not yet implemented for f64") }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToIntChannel for float {
|
||||||
|
#[inline] pub fn to_channel_u8(&self) -> u8 { (*self) * (0xFF_u8 as float) as u8 }
|
||||||
|
#[inline] pub fn to_channel_u16(&self) -> u16 { (*self) * (0xFFFF_u16 as float) as u16 }
|
||||||
|
#[inline] pub fn to_channel_u32(&self) -> u32 { fail!(~"to_channel_u32 not yet implemented for float") }
|
||||||
|
#[inline] pub fn to_channel_u64(&self) -> u64 { fail!(~"to_channel_u64 not yet implemented for float") }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait FloatChannel: Float + Channel + ToFloatChannel {
|
||||||
|
pub fn from<T:ToFloatChannel>(val: T) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FloatChannel for f32 {
|
||||||
|
#[inline] pub fn from<T:ToFloatChannel>(val: T) -> f32 { val.to_channel_f32() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FloatChannel for f64 {
|
||||||
|
#[inline] pub fn from<T:ToFloatChannel>(val: T) -> f64 { val.to_channel_f64() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ToFloatChannel {
|
||||||
|
pub fn to_channel_f32(&self) -> f32;
|
||||||
|
pub fn to_channel_f64(&self) -> f64;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToFloatChannel for u8 {
|
||||||
|
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self as f32) / (0xFF as f32) }
|
||||||
|
#[inline] pub fn to_channel_f64(&self) -> f64 { (*self as f64) / (0xFF as f64) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToFloatChannel for u16 {
|
||||||
|
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self) / 0xFFFF as f32 }
|
||||||
|
#[inline] pub fn to_channel_f64(&self) -> f64 { (*self) / 0xFFFF as f64 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToFloatChannel for u32 {
|
||||||
|
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self) / 0xFFFF_FFFF as f32 }
|
||||||
|
#[inline] pub fn to_channel_f64(&self) -> f64 { (*self) / 0xFFFF_FFFF as f64 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToFloatChannel for u64 {
|
||||||
|
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self) / 0xFFFF_FFFF_FFFF_FFFF_u64 as f32 }
|
||||||
|
#[inline] pub fn to_channel_f64(&self) -> f64 { (*self) / 0xFFFF_FFFF_FFFF_FFFF_u64 as f64 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToFloatChannel for f32 {
|
||||||
|
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self) }
|
||||||
|
#[inline] pub fn to_channel_f64(&self) -> f64 { (*self) as f64 }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToFloatChannel for f64 {
|
||||||
|
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self) as f32 }
|
||||||
|
#[inline] pub fn to_channel_f64(&self) -> f64 { (*self) }
|
||||||
}
|
}
|
|
@ -13,7 +13,8 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
pub use self::channel::Channel;
|
pub use self::channel::{Channel, IntChannel, FloatChannel};
|
||||||
|
pub use self::channel::{ToChannel, ToIntChannel, ToFloatChannel};
|
||||||
pub use self::hsv::{HSV, ToHSV};
|
pub use self::hsv::{HSV, ToHSV};
|
||||||
pub use self::hsva::{HSVA, ToHSVA};
|
pub use self::hsva::{HSVA, ToHSVA};
|
||||||
pub use self::rgb::{RGB, ToRGB};
|
pub use self::rgb::{RGB, ToRGB};
|
||||||
|
@ -28,3 +29,8 @@ pub mod rgb;
|
||||||
pub mod rgba;
|
pub mod rgba;
|
||||||
pub mod srgb;
|
pub mod srgb;
|
||||||
pub mod srgba;
|
pub mod srgba;
|
||||||
|
|
||||||
|
// pub trait Color<T>: Eq {
|
||||||
|
// pub fn inverse(&self) -> Self;
|
||||||
|
// pub fn invert_self(&mut self);
|
||||||
|
// }
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
|
|
||||||
use std::num;
|
use std::num;
|
||||||
|
|
||||||
use color::{Channel, RGB, ToRGB};
|
use color::{Channel, FloatChannel};
|
||||||
|
use color::{RGB, ToRGB};
|
||||||
|
|
||||||
#[path = "../num_macros.rs"]
|
#[path = "../num_macros.rs"]
|
||||||
mod num_macros;
|
mod num_macros;
|
||||||
|
@ -29,38 +30,51 @@ impl<T> HSV<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToHSV<T> {
|
pub trait ToHSV {
|
||||||
pub fn to_hsv(&self) -> HSV<T>;
|
pub fn to_hsv<U:Clone + FloatChannel>(&self) -> HSV<U>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T:Clone + Channel + Float> ToRGB<T> for HSV<T> {
|
impl<T:Clone + FloatChannel> ToHSV for HSV<T> {
|
||||||
pub fn to_rgb(&self) -> RGB<T> {
|
#[inline]
|
||||||
// Algorithm taken from the Wikipedia article on HSL and HSV:
|
pub fn to_hsv<U:Clone + FloatChannel>(&self) -> HSV<U> {
|
||||||
// http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV
|
HSV::new(FloatChannel::from((*self).h.clone()),
|
||||||
|
FloatChannel::from((*self).s.clone()),
|
||||||
let chr = (*self).v * (*self).s;
|
FloatChannel::from((*self).v.clone()))
|
||||||
let h = (*self).h / num::cast(60);
|
|
||||||
|
|
||||||
// the 2nd largest component
|
|
||||||
let x = chr * (one!(T) - ((h % two!(T)) - one!(T)).abs());
|
|
||||||
|
|
||||||
let mut color_rgb = cond! (
|
|
||||||
(h < num::cast(1)) { RGB::new(chr.clone(), x, zero!(T)) }
|
|
||||||
(h < num::cast(2)) { RGB::new(x, chr.clone(), zero!(T)) }
|
|
||||||
(h < num::cast(3)) { RGB::new(zero!(T), chr.clone(), x) }
|
|
||||||
(h < num::cast(4)) { RGB::new(zero!(T), x, chr.clone()) }
|
|
||||||
(h < num::cast(5)) { RGB::new(x, zero!(T), chr.clone()) }
|
|
||||||
(h < num::cast(6)) { RGB::new(chr.clone(), zero!(T), x) }
|
|
||||||
_ { RGB::new(zero!(T), zero!(T), zero!(T)) }
|
|
||||||
);
|
|
||||||
|
|
||||||
// match the value by adding the same amount to each component
|
|
||||||
let mn = (*self).v - chr;
|
|
||||||
|
|
||||||
color_rgb.r = color_rgb.r + mn;
|
|
||||||
color_rgb.g = color_rgb.g + mn;
|
|
||||||
color_rgb.b = color_rgb.b + mn;
|
|
||||||
|
|
||||||
color_rgb
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T:Clone + FloatChannel> ToRGB for HSV<T> {
|
||||||
|
pub fn to_rgb<U:Clone + Channel>(&self) -> RGB<U> {
|
||||||
|
to_rgb(self.to_hsv::<T>()).to_rgb::<U>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
priv fn to_rgb<T:Clone + Float>(color: HSV<T>) -> RGB<T> {
|
||||||
|
// Algorithm taken from the Wikipedia article on HSL and HSV:
|
||||||
|
// http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV
|
||||||
|
|
||||||
|
let chr = color.v * color.s;
|
||||||
|
let h = color.h / num::cast(60);
|
||||||
|
|
||||||
|
// the 2nd largest component
|
||||||
|
let x = chr * (one!(T) - ((h % two!(T)) - one!(T)).abs());
|
||||||
|
|
||||||
|
let mut color_rgb = cond! (
|
||||||
|
(h < num::cast(1)) { RGB::new(chr.clone(), x, zero!(T)) }
|
||||||
|
(h < num::cast(2)) { RGB::new(x, chr.clone(), zero!(T)) }
|
||||||
|
(h < num::cast(3)) { RGB::new(zero!(T), chr.clone(), x) }
|
||||||
|
(h < num::cast(4)) { RGB::new(zero!(T), x, chr.clone()) }
|
||||||
|
(h < num::cast(5)) { RGB::new(x, zero!(T), chr.clone()) }
|
||||||
|
(h < num::cast(6)) { RGB::new(chr.clone(), zero!(T), x) }
|
||||||
|
_ { RGB::new(zero!(T), zero!(T), zero!(T)) }
|
||||||
|
);
|
||||||
|
|
||||||
|
// match the value by adding the same amount to each component
|
||||||
|
let mn = color.v - chr;
|
||||||
|
|
||||||
|
color_rgb.r = color_rgb.r + mn;
|
||||||
|
color_rgb.g = color_rgb.g + mn;
|
||||||
|
color_rgb.b = color_rgb.b + mn;
|
||||||
|
|
||||||
|
color_rgb
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
|
|
||||||
use std::cast;
|
use std::cast;
|
||||||
|
|
||||||
use color::{Channel, HSV, ToHSV, ToRGB, RGBA, ToRGBA};
|
use color::{Channel, FloatChannel};
|
||||||
|
use color::{HSV, ToHSV, RGB, ToRGB, RGBA, ToRGBA};
|
||||||
|
|
||||||
#[path = "../num_macros.rs"]
|
#[path = "../num_macros.rs"]
|
||||||
mod num_macros;
|
mod num_macros;
|
||||||
|
@ -30,29 +31,33 @@ impl<T> HSVA<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToHSVA<T> {
|
pub trait ToHSVA {
|
||||||
pub fn to_hsva(&self) -> HSVA<T>;
|
pub fn to_hsva<U:Clone + FloatChannel>(&self) -> HSVA<U>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T:Clone + Channel, C: ToHSV<T>> ToHSVA<T> for (C, T) {
|
impl<C: ToHSV, T:Clone + FloatChannel> ToHSVA for (C, T) {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_hsva(&self) -> HSVA<T> {
|
pub fn to_hsva<U:Clone + FloatChannel>(&self) -> HSVA<U> {
|
||||||
match *self {
|
match *self {
|
||||||
(ref c, ref a) => unsafe {
|
(ref c, ref a) => unsafe {
|
||||||
cast::transmute((c.to_hsv(), a.clone()))
|
cast::transmute::<(HSV<U>, U), HSVA<U>>(
|
||||||
|
(c.to_hsv::<U>(), Channel::from(a.clone()))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T:Clone + Channel + Float> ToRGBA<T> for HSVA<T> {
|
impl<T:Clone + FloatChannel> ToRGBA for HSVA<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_rgba(&self) -> RGBA<T> {
|
pub fn to_rgba<U:Clone + Channel>(&self) -> RGBA<U> {
|
||||||
match unsafe {
|
match unsafe {
|
||||||
cast::transmute::<&HSVA<T>, &(HSV<T>, T)>(self)
|
cast::transmute::<&HSVA<T>, &(HSV<T>, T)>(self)
|
||||||
} {
|
} {
|
||||||
&(ref c, ref a) => unsafe {
|
&(ref c, ref a) => unsafe {
|
||||||
cast::transmute((c.to_rgb(), a.clone()))
|
cast::transmute::<(RGB<U>, U), RGBA<U>>(
|
||||||
|
(c.to_rgb::<U>(), Channel::from(a.clone()))
|
||||||
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
|
|
||||||
use std::num;
|
use std::num;
|
||||||
|
|
||||||
use color::{Channel, HSV, ToHSV};
|
use color::{Channel, FloatChannel};
|
||||||
|
use color::{HSV, ToHSV};
|
||||||
|
|
||||||
#[path = "../num_macros.rs"]
|
#[path = "../num_macros.rs"]
|
||||||
mod num_macros;
|
mod num_macros;
|
||||||
|
@ -30,32 +31,46 @@ impl<T> RGB<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToRGB<T> {
|
pub trait ToRGB {
|
||||||
pub fn to_rgb(&self) -> RGB<T>;
|
pub fn to_rgb<U:Clone + Channel>(&self) -> RGB<U>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T:Clone + Channel + Float> ToHSV<T> for RGB<T> {
|
impl<T:Clone + Channel> ToRGB for RGB<T> {
|
||||||
pub fn to_hsv(&self) -> HSV<T> {
|
#[inline]
|
||||||
// Algorithm taken from the Wikipedia article on HSL and HSV:
|
pub fn to_rgb<U:Clone + Channel>(&self) -> RGB<U> {
|
||||||
// http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV
|
RGB::new(Channel::from((*self).r.clone()),
|
||||||
|
Channel::from((*self).g.clone()),
|
||||||
let mx = (*self).r.max(&(*self).g).max(&(*self).b);
|
Channel::from((*self).b.clone()))
|
||||||
let mn = (*self).r.min(&(*self).g).min(&(*self).b);
|
}
|
||||||
let chr = mx - mn;
|
}
|
||||||
|
|
||||||
if chr != zero!(T) {
|
impl<T:Clone + FloatChannel> ToHSV for RGB<T> {
|
||||||
let h = cond! (
|
#[inline]
|
||||||
((*self).r == mx) { (((*self).g - (*self).b) / chr) % num::cast(6) }
|
pub fn to_hsv<U:Clone + FloatChannel>(&self) -> HSV<U> {
|
||||||
((*self).g == mx) { (((*self).b - (*self).r) / chr) + num::cast(2) }
|
to_hsv(self.to_rgb::<U>())
|
||||||
_ /* (*self).b == mx */ { (((*self).r - (*self).g) / chr) + num::cast(4) }
|
}
|
||||||
) * num::cast(60);
|
}
|
||||||
|
|
||||||
let s = chr / mx;
|
priv fn to_hsv<T:Clone + Float>(color: RGB<T>) -> HSV<T> {
|
||||||
|
// Algorithm taken from the Wikipedia article on HSL and HSV:
|
||||||
HSV::new(h, s, mx)
|
// http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV
|
||||||
|
|
||||||
} else {
|
let mx = color.r.max(&color.g).max(&color.b);
|
||||||
HSV::new(zero!(T), zero!(T), mx)
|
let mn = color.r.min(&color.g).min(&color.b);
|
||||||
}
|
let chr = mx - mn;
|
||||||
|
|
||||||
|
if chr != zero!(T) {
|
||||||
|
let h = cond! (
|
||||||
|
(color.r == mx) { ((color.g - color.b) / chr) % num::cast(6) }
|
||||||
|
(color.g == mx) { ((color.b - color.r) / chr) + num::cast(2) }
|
||||||
|
_ /* color.b == mx */ { ((color.r - color.g) / chr) + num::cast(4) }
|
||||||
|
) * num::cast(60);
|
||||||
|
|
||||||
|
let s = chr / mx;
|
||||||
|
|
||||||
|
HSV::new(h, s, mx)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
HSV::new(zero!(T), zero!(T), mx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
|
|
||||||
use std::cast;
|
use std::cast;
|
||||||
|
|
||||||
use color::{Channel, RGB, ToRGB, ToHSV, HSVA, ToHSVA};
|
use color::{Channel, FloatChannel};
|
||||||
|
use color::{RGB, ToRGB, HSV, ToHSV, HSVA, ToHSVA};
|
||||||
|
|
||||||
#[path = "../num_macros.rs"]
|
#[path = "../num_macros.rs"]
|
||||||
mod num_macros;
|
mod num_macros;
|
||||||
|
@ -30,29 +31,33 @@ impl<T> RGBA<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToRGBA<T> {
|
pub trait ToRGBA {
|
||||||
pub fn to_rgba(&self) -> RGBA<T>;
|
pub fn to_rgba<U:Clone + Channel>(&self) -> RGBA<U>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T:Clone + Channel, C: ToRGB<T>> ToRGBA<T> for (C, T) {
|
impl<C: ToRGB, T:Clone + Channel> ToRGBA for (C, T) {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_rgba(&self) -> RGBA<T> {
|
pub fn to_rgba<U:Clone + Channel>(&self) -> RGBA<U> {
|
||||||
match *self {
|
match *self {
|
||||||
(ref c, ref a) => unsafe {
|
(ref c, ref a) => unsafe {
|
||||||
cast::transmute((c.to_rgb(), a.clone()))
|
cast::transmute::<(RGB<U>, U), RGBA<U>>(
|
||||||
|
(c.to_rgb::<U>(), Channel::from(a.clone()))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T:Clone + Channel + Float> ToHSVA<T> for RGBA<T> {
|
impl<T:Clone + FloatChannel> ToHSVA for RGBA<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_hsva(&self) -> HSVA<T> {
|
pub fn to_hsva<U:Clone + FloatChannel>(&self) -> HSVA<U> {
|
||||||
match unsafe {
|
match unsafe {
|
||||||
cast::transmute::<&RGBA<T>, &(RGB<T>, T)>(self)
|
cast::transmute::<&RGBA<T>, &(RGB<T>, T)>(self)
|
||||||
} {
|
} {
|
||||||
&(ref c, ref a) => unsafe {
|
&(ref c, ref a) => unsafe {
|
||||||
cast::transmute((c.to_hsv(), a.clone()))
|
cast::transmute::<(HSV<U>, U), HSVA<U>>(
|
||||||
|
(c.to_hsv::<U>(), FloatChannel::from(a.clone()))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue