Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split the Component trait into more specific traits #161

Merged
merged 1 commit into from Jan 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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););