Simplify color::channel traits

This commit is contained in:
Brendan Zabarauskas 2013-07-09 22:50:20 +10:00
parent 49715e6479
commit d65aa944b9
4 changed files with 45 additions and 172 deletions

View file

@ -13,176 +13,47 @@
// 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.
/// A color channel pub trait Channel: Num {
pub trait Channel: Num + ToChannel { pub fn from<T:Channel>(chan: T) -> Self;
/// Convert a channel to the enclosing type
///
/// # Example
///
/// ~~~
/// let chan: f32 = Channel::from(0xFFFFu16);
/// assert chan == 1.0f32;
/// ~~~
pub fn from<T: ToChannel>(val: T) -> Self;
}
impl Channel for u8 {
#[inline] pub fn from<T: ToChannel>(val: T) -> u8 { val.to_channel_u8() }
}
impl Channel for u16 {
#[inline] pub fn from<T: ToChannel>(val: T) -> u16 { val.to_channel_u16() }
}
impl Channel for u32 {
#[inline] pub fn from<T: ToChannel>(val: T) -> u32 { val.to_channel_u32() }
}
impl Channel for u64 {
#[inline] pub fn from<T: ToChannel>(val: T) -> u64 { val.to_channel_u64() }
}
impl Channel for f32 {
#[inline] pub fn from<T: ToChannel>(val: T) -> f32 { val.to_channel_f32() }
}
impl Channel for f64 {
#[inline] pub fn from<T: ToChannel>(val: T) -> f64 { val.to_channel_f64() }
}
pub trait ToChannel: ToIntChannel + ToFloatChannel {}
impl ToChannel for u8 {}
impl ToChannel for u16 {}
impl ToChannel for u32 {}
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_u8(&self) -> u8;
pub fn to_channel_u16(&self) -> u16; 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_f32(&self) -> f32;
pub fn to_channel_f64(&self) -> f64; pub fn to_channel_f64(&self) -> f64;
} }
impl ToFloatChannel for u8 { impl Channel for u8 {
#[inline] pub fn from<T:Channel>(chan: T) -> u8 { chan.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_f32(&self) -> f32 { (*self as f32) / (0xFF as f32) } #[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_f64(&self) -> f64 { (*self as f64) / (0xFF as f64) }
} }
impl ToFloatChannel for u16 { impl Channel for u16 {
#[inline] pub fn from<T:Channel>(chan: T) -> u16 { chan.to_channel_u16() }
#[inline] pub fn to_channel_u8(&self) -> u8 { (*self >> 8) as u8 }
#[inline] pub fn to_channel_u16(&self) -> u16 { (*self) }
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self) / 0xFFFF as f32 } #[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_f64(&self) -> f64 { (*self) / 0xFFFF as f64 }
} }
impl ToFloatChannel for u32 { impl Channel for f32 {
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self) / 0xFFFF_FFFF as f32 } #[inline] pub fn from<T:Channel>(chan: T) -> f32 { chan.to_channel_f32() }
#[inline] pub fn to_channel_f64(&self) -> f64 { (*self) / 0xFFFF_FFFF as f64 }
}
impl ToFloatChannel for u64 { #[inline] pub fn to_channel_u8(&self) -> u8 { (*self) * (0xFF_u8 as f32) as u8 }
#[inline] pub fn to_channel_f32(&self) -> f32 { (*self) / 0xFFFF_FFFF_FFFF_FFFF_u64 as f32 } #[inline] pub fn to_channel_u16(&self) -> u16 { (*self) * (0xFFFF_u16 as f32) as u16 }
#[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_f32(&self) -> f32 { (*self) }
#[inline] pub fn to_channel_f64(&self) -> f64 { (*self) as f64 } #[inline] pub fn to_channel_f64(&self) -> f64 { (*self) as f64 }
} }
impl ToFloatChannel for f64 { impl Channel for f64 {
#[inline] pub fn from<T:Channel>(chan: T) -> f64 { chan.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_f32(&self) -> f32 { (*self) as f32 } #[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_f64(&self) -> f64 { (*self) }
} }

View file

@ -13,8 +13,7 @@
// 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, IntChannel, FloatChannel}; pub use self::channel::Channel;
pub use self::channel::{ToChannel, ToIntChannel, ToFloatChannel};
pub use self::hsv::{HSV, ToHSV, HSVA, ToHSVA}; pub use self::hsv::{HSV, ToHSV, HSVA, ToHSVA};
pub use self::rgb::{RGB, ToRGB, RGBA, ToRGBA}; pub use self::rgb::{RGB, ToRGB, RGBA, ToRGBA};
pub use self::srgb::{SRGB, SRGBA}; pub use self::srgb::{SRGB, SRGBA};

View file

@ -16,7 +16,7 @@
use std::num; use std::num;
use std::cast; use std::cast;
use color::{Channel, ToChannel, FloatChannel, ToFloatChannel}; use color::Channel;
use color::{RGB, ToRGB, RGBA, ToRGBA}; use color::{RGB, ToRGB, RGBA, ToRGBA};
#[path = "../num_macros.rs"] #[path = "../num_macros.rs"]
@ -32,19 +32,19 @@ impl<T> HSV<T> {
} }
pub trait ToHSV { pub trait ToHSV {
pub fn to_hsv<U:Clone + FloatChannel>(&self) -> HSV<U>; pub fn to_hsv<U:Clone + Float + Channel>(&self) -> HSV<U>;
} }
impl<T:Clone + ToFloatChannel> ToHSV for HSV<T> { impl<T:Clone + Float + Channel> ToHSV for HSV<T> {
#[inline] #[inline]
pub fn to_hsv<U:Clone + FloatChannel>(&self) -> HSV<U> { pub fn to_hsv<U:Clone + Float + Channel>(&self) -> HSV<U> {
HSV::new(FloatChannel::from((*self).h.clone()), HSV::new(Channel::from((*self).h.clone()),
FloatChannel::from((*self).s.clone()), Channel::from((*self).s.clone()),
FloatChannel::from((*self).v.clone())) Channel::from((*self).v.clone()))
} }
} }
impl<T:Clone + Float + ToChannel> ToRGB for HSV<T> { impl<T:Clone + Float + Channel> ToRGB for HSV<T> {
pub fn to_rgb<U:Clone + Channel>(&self) -> RGB<U> { pub fn to_rgb<U:Clone + Channel>(&self) -> RGB<U> {
// Algorithm taken from the Wikipedia article on HSL and HSV: // Algorithm taken from the Wikipedia article on HSL and HSV:
// http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV // http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV
@ -102,24 +102,24 @@ impl<T> HSVA<T> {
} }
pub trait ToHSVA { pub trait ToHSVA {
pub fn to_hsva<U:Clone + FloatChannel>(&self) -> HSVA<U>; pub fn to_hsva<U:Clone + Float + Channel>(&self) -> HSVA<U>;
} }
impl<C: ToHSV, T:Clone + ToFloatChannel> ToHSVA for (C, T) { impl<C: ToHSV, T:Clone + Float + Channel> ToHSVA for (C, T) {
#[inline] #[inline]
pub fn to_hsva<U:Clone + FloatChannel>(&self) -> HSVA<U> { pub fn to_hsva<U:Clone + Float + Channel>(&self) -> HSVA<U> {
match *self { match *self {
(ref hsv, ref a) => { (ref hsv, ref a) => {
HSVA::from_hsv_a( HSVA::from_hsv_a(
hsv.to_hsv(), hsv.to_hsv(),
FloatChannel::from(a.clone()) Channel::from(a.clone())
) )
} }
} }
} }
} }
impl<T:Clone + Float + ToChannel> ToRGBA for HSVA<T> { impl<T:Clone + Float + Channel> ToRGBA for HSVA<T> {
#[inline] #[inline]
pub fn to_rgba<U:Clone + Channel>(&self) -> RGBA<U> { pub fn to_rgba<U:Clone + Channel>(&self) -> RGBA<U> {
RGBA::from_rgb_a( RGBA::from_rgb_a(

View file

@ -16,7 +16,7 @@
use std::num; use std::num;
use std::cast; use std::cast;
use color::{Channel, ToChannel, FloatChannel}; use color::Channel;
use color::{HSV, ToHSV, HSVA, ToHSVA}; use color::{HSV, ToHSV, HSVA, ToHSVA};
#[path = "../num_macros.rs"] #[path = "../num_macros.rs"]
@ -36,7 +36,7 @@ pub trait ToRGB {
pub fn to_rgb<U:Clone + Channel>(&self) -> RGB<U>; pub fn to_rgb<U:Clone + Channel>(&self) -> RGB<U>;
} }
impl<T:Clone + ToChannel> ToRGB for RGB<T> { impl<T:Clone + Channel> ToRGB for RGB<T> {
#[inline] #[inline]
pub fn to_rgb<U:Clone + Channel>(&self) -> RGB<U> { pub fn to_rgb<U:Clone + Channel>(&self) -> RGB<U> {
RGB::new(Channel::from((*self).r.clone()), RGB::new(Channel::from((*self).r.clone()),
@ -45,9 +45,9 @@ impl<T:Clone + ToChannel> ToRGB for RGB<T> {
} }
} }
impl<T:Clone + ToChannel> ToHSV for RGB<T> { impl<T:Clone + Channel> ToHSV for RGB<T> {
#[inline] #[inline]
pub fn to_hsv<U:Clone + FloatChannel>(&self) -> HSV<U> { pub fn to_hsv<U:Clone + Float + Channel>(&self) -> HSV<U> {
// Algorithm taken from the Wikipedia article on HSL and HSV: // Algorithm taken from the Wikipedia article on HSL and HSV:
// http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV // http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV
@ -103,7 +103,7 @@ pub trait ToRGBA {
pub fn to_rgba<U:Clone + Channel>(&self) -> RGBA<U>; pub fn to_rgba<U:Clone + Channel>(&self) -> RGBA<U>;
} }
impl<C: ToRGB, T:Clone + ToChannel> ToRGBA for (C, T) { impl<C: ToRGB, T:Clone + Channel> ToRGBA for (C, T) {
#[inline] #[inline]
pub fn to_rgba<U:Clone + Channel>(&self) -> RGBA<U> { pub fn to_rgba<U:Clone + Channel>(&self) -> RGBA<U> {
match *self { match *self {
@ -114,12 +114,15 @@ impl<C: ToRGB, T:Clone + ToChannel> ToRGBA for (C, T) {
} }
} }
impl<T:Clone + ToChannel> ToHSVA for RGBA<T> { impl<T:Clone + Channel> ToHSVA for RGBA<T> {
#[inline] #[inline]
pub fn to_hsva<U:Clone + FloatChannel>(&self) -> HSVA<U> { pub fn to_hsva<U:Clone + Float + Channel>(&self) -> HSVA<U> {
HSVA::from_hsv_a( HSVA::from_hsv_a(
self.rgb().to_hsv(), self.rgb().to_hsv(),
Channel::from((*self).a.clone()) Channel::from((*self).a.clone())
) )
} }
} }
// 0xFF_FF_FF_FF_u32
// 0xFFFF_FFFF_FFFF_FFFF_u64