From 2ca90cb75072fbd0e5ba60431b253627424bcf5d Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Tue, 9 Jul 2013 16:42:19 +1000 Subject: [PATCH] Fix color channel conversions --- src/color/channel.rs | 218 ++++++++++++++++++++++++++++--------------- src/color/color.rs | 8 +- src/color/hsv.rs | 78 +++++++++------- src/color/hsva.rs | 23 +++-- src/color/rgb.rs | 67 +++++++------ src/color/rgba.rs | 23 +++-- 6 files changed, 265 insertions(+), 152 deletions(-) diff --git a/src/color/channel.rs b/src/color/channel.rs index 5b21c71..227b1c9 100644 --- a/src/color/channel.rs +++ b/src/color/channel.rs @@ -14,7 +14,7 @@ // limitations under the License. /// A color channel -pub trait Channel: Num { +pub trait Channel: Num + ToChannel{ /// Convert a channel to the enclosing type /// /// # Example @@ -23,98 +23,166 @@ pub trait Channel: Num { /// let chan: f32 = Channel::from(0xFFFFu16); /// assert chan == 1.0f32; /// ~~~ - pub fn from(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; + pub fn from(val: T) -> Self; } impl Channel for u8 { - #[inline] pub fn from(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) } + #[inline] pub fn from(val: T) -> u8 { val.to_channel_u8() } } impl Channel for u16 { - #[inline] pub fn from(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 } + #[inline] pub fn from(val: T) -> u16 { val.to_channel_u16() } } impl Channel for u32 { - #[inline] pub fn from(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 } + #[inline] pub fn from(val: T) -> u32 { val.to_channel_u32() } } impl Channel for u64 { - #[inline] pub fn from(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 } + #[inline] pub fn from(val: T) -> u64 { val.to_channel_u64() } } impl Channel for f32 { - #[inline] pub fn from(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 } + #[inline] pub fn from(val: T) -> f32 { val.to_channel_f32() } } impl Channel for f64 { - #[inline] pub fn from(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 } + #[inline] pub fn from(val: T) -> f64 { val.to_channel_f64() } } -impl Channel for float { - #[inline] pub fn from(val: T) -> float { val.to_channel_float() } +pub trait ToChannel: ToIntChannel + ToFloatChannel {} - #[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") } - #[inline] pub fn to_channel_f32(&self) -> f32 { (*self) as f32 } - #[inline] pub fn to_channel_f64(&self) -> f64 { (*self) as f64 } - #[inline] pub fn to_channel_float(&self) -> float { (*self) } -} \ No newline at end of file +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(val: T) -> Self; +} + +impl IntChannel for u8 { + #[inline] pub fn from(val: T) -> u8 { val.to_channel_u8() } +} + +impl IntChannel for u16 { + #[inline] pub fn from(val: T) -> u16 { val.to_channel_u16() } +} + +impl IntChannel for u32 { + #[inline] pub fn from(val: T) -> u32 { val.to_channel_u32() } +} + +impl IntChannel for u64 { + #[inline] pub fn from(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(val: T) -> Self; +} + +impl FloatChannel for f32 { + #[inline] pub fn from(val: T) -> f32 { val.to_channel_f32() } +} + +impl FloatChannel for f64 { + #[inline] pub fn from(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) } +} diff --git a/src/color/color.rs b/src/color/color.rs index a29006b..cf691c7 100644 --- a/src/color/color.rs +++ b/src/color/color.rs @@ -13,7 +13,8 @@ // See the License for the specific language governing permissions and // 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::hsva::{HSVA, ToHSVA}; pub use self::rgb::{RGB, ToRGB}; @@ -28,3 +29,8 @@ pub mod rgb; pub mod rgba; pub mod srgb; pub mod srgba; + +// pub trait Color: Eq { +// pub fn inverse(&self) -> Self; +// pub fn invert_self(&mut self); +// } diff --git a/src/color/hsv.rs b/src/color/hsv.rs index 950b08d..41537c1 100644 --- a/src/color/hsv.rs +++ b/src/color/hsv.rs @@ -15,7 +15,8 @@ use std::num; -use color::{Channel, RGB, ToRGB}; +use color::{Channel, FloatChannel}; +use color::{RGB, ToRGB}; #[path = "../num_macros.rs"] mod num_macros; @@ -29,38 +30,51 @@ impl HSV { } } -pub trait ToHSV { - pub fn to_hsv(&self) -> HSV; +pub trait ToHSV { + pub fn to_hsv(&self) -> HSV; } -impl ToRGB for HSV { - pub fn to_rgb(&self) -> RGB { - // Algorithm taken from the Wikipedia article on HSL and HSV: - // http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV - - let chr = (*self).v * (*self).s; - 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 ToHSV for HSV { + #[inline] + pub fn to_hsv(&self) -> HSV { + HSV::new(FloatChannel::from((*self).h.clone()), + FloatChannel::from((*self).s.clone()), + FloatChannel::from((*self).v.clone())) } } + +impl ToRGB for HSV { + pub fn to_rgb(&self) -> RGB { + to_rgb(self.to_hsv::()).to_rgb::() + } +} + +priv fn to_rgb(color: HSV) -> RGB { + // 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 +} diff --git a/src/color/hsva.rs b/src/color/hsva.rs index e4680ff..33902ee 100644 --- a/src/color/hsva.rs +++ b/src/color/hsva.rs @@ -15,7 +15,8 @@ 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"] mod num_macros; @@ -30,29 +31,33 @@ impl HSVA { } } -pub trait ToHSVA { - pub fn to_hsva(&self) -> HSVA; +pub trait ToHSVA { + pub fn to_hsva(&self) -> HSVA; } -impl> ToHSVA for (C, T) { +impl ToHSVA for (C, T) { #[inline] - pub fn to_hsva(&self) -> HSVA { + pub fn to_hsva(&self) -> HSVA { match *self { (ref c, ref a) => unsafe { - cast::transmute((c.to_hsv(), a.clone())) + cast::transmute::<(HSV, U), HSVA>( + (c.to_hsv::(), Channel::from(a.clone())) + ) } } } } -impl ToRGBA for HSVA { +impl ToRGBA for HSVA { #[inline] - pub fn to_rgba(&self) -> RGBA { + pub fn to_rgba(&self) -> RGBA { match unsafe { cast::transmute::<&HSVA, &(HSV, T)>(self) } { &(ref c, ref a) => unsafe { - cast::transmute((c.to_rgb(), a.clone())) + cast::transmute::<(RGB, U), RGBA>( + (c.to_rgb::(), Channel::from(a.clone())) + ) }, } } diff --git a/src/color/rgb.rs b/src/color/rgb.rs index 9313ec5..0156724 100644 --- a/src/color/rgb.rs +++ b/src/color/rgb.rs @@ -15,7 +15,8 @@ use std::num; -use color::{Channel, HSV, ToHSV}; +use color::{Channel, FloatChannel}; +use color::{HSV, ToHSV}; #[path = "../num_macros.rs"] mod num_macros; @@ -30,32 +31,46 @@ impl RGB { } } -pub trait ToRGB { - pub fn to_rgb(&self) -> RGB; +pub trait ToRGB { + pub fn to_rgb(&self) -> RGB; } -impl ToHSV for RGB { - pub fn to_hsv(&self) -> HSV { - // Algorithm taken from the Wikipedia article on HSL and HSV: - // http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV - - let mx = (*self).r.max(&(*self).g).max(&(*self).b); - let mn = (*self).r.min(&(*self).g).min(&(*self).b); - let chr = mx - mn; - - if chr != zero!(T) { - let h = cond! ( - ((*self).r == mx) { (((*self).g - (*self).b) / chr) % num::cast(6) } - ((*self).g == mx) { (((*self).b - (*self).r) / chr) + num::cast(2) } - _ /* (*self).b == mx */ { (((*self).r - (*self).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) - } +impl ToRGB for RGB { + #[inline] + pub fn to_rgb(&self) -> RGB { + RGB::new(Channel::from((*self).r.clone()), + Channel::from((*self).g.clone()), + Channel::from((*self).b.clone())) + } +} + +impl ToHSV for RGB { + #[inline] + pub fn to_hsv(&self) -> HSV { + to_hsv(self.to_rgb::()) + } +} + +priv fn to_hsv(color: RGB) -> HSV { + // Algorithm taken from the Wikipedia article on HSL and HSV: + // http://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV + + let mx = color.r.max(&color.g).max(&color.b); + 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) } } diff --git a/src/color/rgba.rs b/src/color/rgba.rs index beed60c..3938091 100644 --- a/src/color/rgba.rs +++ b/src/color/rgba.rs @@ -15,7 +15,8 @@ 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"] mod num_macros; @@ -30,29 +31,33 @@ impl RGBA { } } -pub trait ToRGBA { - pub fn to_rgba(&self) -> RGBA; +pub trait ToRGBA { + pub fn to_rgba(&self) -> RGBA; } -impl> ToRGBA for (C, T) { +impl ToRGBA for (C, T) { #[inline] - pub fn to_rgba(&self) -> RGBA { + pub fn to_rgba(&self) -> RGBA { match *self { (ref c, ref a) => unsafe { - cast::transmute((c.to_rgb(), a.clone())) + cast::transmute::<(RGB, U), RGBA>( + (c.to_rgb::(), Channel::from(a.clone())) + ) } } } } -impl ToHSVA for RGBA { +impl ToHSVA for RGBA { #[inline] - pub fn to_hsva(&self) -> HSVA { + pub fn to_hsva(&self) -> HSVA { match unsafe { cast::transmute::<&RGBA, &(RGB, T)>(self) } { &(ref c, ref a) => unsafe { - cast::transmute((c.to_hsv(), a.clone())) + cast::transmute::<(HSV, U), HSVA>( + (c.to_hsv::(), FloatChannel::from(a.clone())) + ) } } }