Skip to content

Commit

Permalink
Split the Component trait into more specific traits
Browse files Browse the repository at this point in the history
  • Loading branch information
Ogeon committed Jan 19, 2020
1 parent 0279591 commit 09043a8
Show file tree
Hide file tree
Showing 25 changed files with 995 additions and 882 deletions.
13 changes: 7 additions & 6 deletions palette/src/blend/blend.rs
Expand Up @@ -2,7 +2,7 @@ use float::Float;
use num_traits::{One, Zero};

use blend::{BlendFunction, PreAlpha};
use {cast, clamp, ComponentWise};
use {clamp, ComponentWise};

///A trait for colors that can be blended together.
///
Expand Down Expand Up @@ -353,6 +353,10 @@ where
let one = <Self::Color as ComponentWise>::Scalar::one();
let zero = <Self::Color as ComponentWise>::Scalar::zero();
let two = one + one;
let three = two + one;
let four = two + two;
let twelve = four + four + four;
let sixteen = twelve + four;

let src = self.into_premultiplied();
let dst = other.into_premultiplied();
Expand All @@ -369,14 +373,11 @@ where
b * (src.alpha + (two * a - src.alpha) * (one - m))
+ a * (one - dst.alpha)
+ b * (one - src.alpha)
} else if b * cast(4.0) <= dst.alpha {
} else if b * four <= dst.alpha {
let m2 = m * m;
let m3 = m2 * m;

dst.alpha
* (two * a - src.alpha)
* (m3 * cast(16.0) - m2 * cast(12.0) - m * cast(3.0))
+ a
dst.alpha * (two * a - src.alpha) * (m3 * sixteen - m2 * twelve - m * three) + a
- a * dst.alpha
+ b
} else {
Expand Down
75 changes: 41 additions & 34 deletions palette/src/chromatic_adaptation.rs
Expand Up @@ -24,9 +24,10 @@
//!```
use float::Float;

use {cast, Component, FromColor, IntoColor, Xyz};
use from_f64;
use matrix::{multiply_3x3, multiply_xyz, Mat3};
use white_point::WhitePoint;
use matrix::{multiply_xyz, Mat3, multiply_3x3};
use {FloatComponent, FromColor, IntoColor, Xyz};

///Chromatic adaptation methods implemented in the library
pub enum Method {
Expand All @@ -50,7 +51,7 @@ pub struct ConeResponseMatrices<T: Float> {
///one illuminant to another (Swp -> Dwp)
pub trait TransformMatrix<Swp, Dwp, T>
where
T: Component + Float,
T: FloatComponent,
Swp: WhitePoint,
Dwp: WhitePoint,
{
Expand Down Expand Up @@ -86,7 +87,7 @@ where

impl<Swp, Dwp, T> TransformMatrix<Swp, Dwp, T> for Method
where
T: Component + Float,
T: FloatComponent,
Swp: WhitePoint,
Dwp: WhitePoint,
{
Expand All @@ -95,38 +96,44 @@ where
match *self {
Method::Bradford => {
ConeResponseMatrices::<T> {
ma: [cast(0.8951000), cast(0.2664000), cast(-0.1614000),
cast(-0.7502000), cast(1.7135000), cast(0.0367000),
cast(0.0389000), cast(-0.0685000), cast(1.0296000)
],
inv_ma: [cast(0.9869929), cast(-0.1470543), cast(0.1599627),
cast(0.4323053), cast(0.5183603), cast(0.0492912),
cast(-0.0085287), cast(0.0400428), cast(0.9684867)
],
ma: [
from_f64(0.8951000), from_f64(0.2664000), from_f64(-0.1614000),
from_f64(-0.7502000), from_f64(1.7135000), from_f64(0.0367000),
from_f64(0.0389000), from_f64(-0.0685000), from_f64(1.0296000)
],
inv_ma: [
from_f64(0.9869929), from_f64(-0.1470543), from_f64(0.1599627),
from_f64(0.4323053), from_f64(0.5183603), from_f64(0.0492912),
from_f64(-0.0085287), from_f64(0.0400428), from_f64(0.9684867)
],
}
}
Method::VonKries => {
ConeResponseMatrices::<T> {
ma: [cast(0.4002400), cast(0.7076000), cast(-0.0808100),
cast(-0.2263000), cast(1.1653200), cast(0.0457000),
cast(0.0000000), cast(0.0000000), cast(0.9182200)
],
inv_ma: [cast(1.8599364), cast(-1.1293816), cast(0.2198974),
cast(0.3611914), cast(0.6388125), cast(-0.0000064),
cast(0.0000000), cast(0.0000000), cast(1.0890636)
],
ma: [
from_f64(0.4002400), from_f64(0.7076000), from_f64(-0.0808100),
from_f64(-0.2263000), from_f64(1.1653200), from_f64(0.0457000),
from_f64(0.0000000), from_f64(0.0000000), from_f64(0.9182200)
],
inv_ma: [
from_f64(1.8599364), from_f64(-1.1293816), from_f64(0.2198974),
from_f64(0.3611914), from_f64(0.6388125), from_f64(-0.0000064),
from_f64(0.0000000), from_f64(0.0000000), from_f64(1.0890636)
],
}
}
Method::XyzScaling => {
ConeResponseMatrices::<T> {
ma: [cast(1.0000000), cast(0.0000000), cast(0.0000000),
cast(0.0000000), cast(1.0000000), cast(0.0000000),
cast(0.0000000), cast(0.0000000), cast(1.0000000)
],
inv_ma: [cast(1.0000000), cast(0.0000000), cast(0.0000000),
cast(0.0000000), cast(1.0000000), cast(0.0000000),
cast(0.0000000), cast(0.0000000), cast(1.0000000)
],
ma: [
from_f64(1.0000000), from_f64(0.0000000), from_f64(0.0000000),
from_f64(0.0000000), from_f64(1.0000000), from_f64(0.0000000),
from_f64(0.0000000), from_f64(0.0000000), from_f64(1.0000000)
],
inv_ma: [
from_f64(1.0000000), from_f64(0.0000000), from_f64(0.0000000),
from_f64(0.0000000), from_f64(1.0000000), from_f64(0.0000000),
from_f64(0.0000000), from_f64(0.0000000), from_f64(1.0000000)
],
}
}
}
Expand All @@ -139,7 +146,7 @@ where
///Uses the bradford method for conversion by default.
pub trait AdaptFrom<S, Swp, Dwp, T>: Sized
where
T: Component + Float,
T: FloatComponent,
Swp: WhitePoint,
Dwp: WhitePoint,
{
Expand All @@ -155,7 +162,7 @@ where

impl<S, D, Swp, Dwp, T> AdaptFrom<S, Swp, Dwp, T> for D
where
T: Component + Float,
T: FloatComponent,
Swp: WhitePoint,
Dwp: WhitePoint,
S: IntoColor<Swp, T>,
Expand All @@ -175,7 +182,7 @@ where
///Uses the bradford method for conversion by default.
pub trait AdaptInto<D, Swp, Dwp, T>: Sized
where
T: Component + Float,
T: FloatComponent,
Swp: WhitePoint,
Dwp: WhitePoint,
{
Expand All @@ -191,7 +198,7 @@ where

impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for S
where
T: Component + Float,
T: FloatComponent,
Swp: WhitePoint,
Dwp: WhitePoint,
D: AdaptFrom<S, Swp, Dwp, T>,
Expand All @@ -204,9 +211,9 @@ where
#[cfg(test)]
mod test {

use Xyz;
use white_point::{D50, D65, A, C};
use super::{AdaptFrom, AdaptInto, Method, TransformMatrix};
use white_point::{A, C, D50, D65};
use Xyz;

#[test]
fn d65_to_d50_matrix_xyz_scaling() {
Expand Down
181 changes: 181 additions & 0 deletions palette/src/component.rs
@@ -0,0 +1,181 @@
use num_traits::Zero;

use float::Float;
use {clamp, FromF64};

/// Common trait for color components.
pub trait Component: Copy + Zero + PartialOrd {
/// The highest displayable value this component type can reach. Higher
/// values are allowed, but they may be lowered to this before
/// converting to another format.
fn max_intensity() -> Self;
}

/// Common trait for floating point color components.
pub trait FloatComponent: Component + Float + FromF64 {}

impl<T: Component + Float + FromF64> FloatComponent for T {}

macro_rules! impl_float_components {
($($ty: ident),+) => {
$(
impl Component for $ty {
fn max_intensity() -> Self {
1.0
}
}
)*
};
}

impl_float_components!(f32, f64);

macro_rules! impl_uint_components {
($($ty: ident),+) => {
$(
impl Component for $ty {
fn max_intensity() -> Self {
core::$ty::MAX
}
}
)*
};
}

impl_uint_components!(u8, u16, u32, u64, u128);

/// Converts from a color component type, while performing the appropriate scaling, rounding and clamping.
///
/// ```
/// use palette::FromComponent;
///
/// // Scales the value up to u8::MAX while converting.
/// let u8_component = u8::from_component(1.0f32);
/// assert_eq!(u8_component, 255);
/// ```
pub trait FromComponent<T: Component> {
/// Converts `other` into `Self`, while performing the appropriate scaling, rounding and clamping.
fn from_component(other: T) -> Self;
}

impl<T: Component, U: IntoComponent<T> + Component> FromComponent<U> for T {
#[inline]
fn from_component(other: U) -> T {
other.into_component()
}
}

/// Converts into a color component type, while performing the appropriate scaling, rounding and clamping.
///
/// ```
/// use palette::IntoComponent;
///
/// // Scales the value up to u8::MAX while converting.
/// let u8_component: u8 = 1.0f32.into_component();
/// assert_eq!(u8_component, 255);
/// ```
pub trait IntoComponent<T: Component> {
/// Converts `self` into `T`, while performing the appropriate scaling, rounding and clamping.
fn into_component(self) -> T;
}

impl<T: Component> IntoComponent<T> for T {
#[inline]
fn into_component(self) -> T {
self
}
}

macro_rules! convert_float_to_uint {
($float: ident; direct ($($direct_target: ident),+); $(via $temporary: ident ($($target: ident),+);)*) => {
$(
impl IntoComponent<$direct_target> for $float {
#[inline]
fn into_component(self) -> $direct_target {
let max = $direct_target::max_intensity() as $float;
let scaled = self * max;
clamp(scaled.round(), 0.0, max) as $direct_target
}
}
)+

$(
$(
impl IntoComponent<$target> for $float {
#[inline]
fn into_component(self) -> $target {
let max = $target::max_intensity() as $temporary;
let scaled = self as $temporary * max;
clamp(scaled.round(), 0.0, max) as $target
}
}
)+
)*
};
}

macro_rules! convert_uint_to_float {
($uint: ident; $(via $temporary: ident ($($target: ident),+);)*) => {
$(
$(
impl IntoComponent<$target> for $uint {
#[inline]
fn into_component(self) -> $target {
let max = $uint::max_intensity() as $temporary;
let scaled = self as $temporary / max;
scaled as $target
}
}
)+
)*
};
}

macro_rules! convert_uint_to_uint {
($uint: ident; $(via $temporary: ident ($($target: ident),+);)*) => {
$(
$(
impl IntoComponent<$target> for $uint {
#[inline]
fn into_component(self) -> $target {
let target_max = $target::max_intensity() as $temporary;
let own_max = $uint::max_intensity() as $temporary;
let scaled = (self as $temporary / own_max) * target_max;
clamp(scaled.round(), 0.0, target_max) as $target
}
}
)+
)*
};
}

impl IntoComponent<f64> for f32 {
#[inline]
fn into_component(self) -> f64 {
self as f64
}
}
convert_float_to_uint!(f32; direct (u8, u16); via f64 (u32, u64, u128););

impl IntoComponent<f32> for f64 {
#[inline]
fn into_component(self) -> f32 {
self as f32
}
}
convert_float_to_uint!(f64; direct (u8, u16, u32, u64, u128););

convert_uint_to_float!(u8; via f32 (f32); via f64 (f64););
convert_uint_to_uint!(u8; via f32 (u16); via f64 (u32, u64, u128););

convert_uint_to_float!(u16; via f32 (f32); via f64 (f64););
convert_uint_to_uint!(u16; via f32 (u8); via f64 (u32, u64, u128););

convert_uint_to_float!(u32; via f64 (f32, f64););
convert_uint_to_uint!(u32; via f64 (u8, u16, u64, u128););

convert_uint_to_float!(u64; via f64 (f32, f64););
convert_uint_to_uint!(u64; via f64 (u8, u16, u32, u128););

convert_uint_to_float!(u128; via f64 (f32, f64););
convert_uint_to_uint!(u128; via f64 (u8, u16, u32, u64););

0 comments on commit 09043a8

Please sign in to comment.