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

Add an Any white point #240

Merged
merged 1 commit into from
Jul 16, 2021
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions palette/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ impl FromColorUnclamped<Color> for Color {
// Convert from any kind of f32 sRGB.
impl<S> FromColorUnclamped<Rgb<S, f32>> for Color
where
S: RgbStandard<Space = encoding::Srgb>,
S: RgbStandard<f32, Space = encoding::Srgb>,
{
fn from_color_unclamped(color: Rgb<S, f32>) -> Color {
let srgb = Srgb::from_color_unclamped(color);
Expand All @@ -298,7 +298,7 @@ where
// Convert into any kind of f32 sRGB.
impl<S> FromColorUnclamped<Color> for Rgb<S, f32>
where
S: RgbStandard<Space = encoding::Srgb>,
S: RgbStandard<f32, Space = encoding::Srgb>,
{
fn from_color_unclamped(color: Color) -> Self {
let srgb = Srgb::new(color.r, color.g, color.b);
Expand Down
8 changes: 4 additions & 4 deletions palette/benches/matrix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ use palette::matrix::{
matrix_inverse, multiply_3x3, multiply_rgb_to_xyz, multiply_xyz, multiply_xyz_to_rgb,
rgb_to_xyz_matrix,
};
use palette::white_point::{WhitePoint, D50, D65};
use palette::white_point::{WhitePoint, D65};
use palette::{LinSrgb, Xyz};

fn matrix(c: &mut Criterion) {
let mut group = c.benchmark_group("Matrix functions");

let inp1 = [0.1, 0.2, 0.3, 0.3, 0.2, 0.1, 0.2, 0.1, 0.3];
let inp2: Xyz<D65, _> = Xyz::new(0.4, 0.6, 0.8);
let inp2 = Xyz::new(0.4, 0.6, 0.8);
let inp3 = [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 2.0, 1.0, 3.0];
let inp4 = [4.0, 5.0, 6.0, 6.0, 5.0, 4.0, 4.0, 6.0, 5.0];
let inverse: [f64; 9] = [3.0, 0.0, 2.0, 2.0, 0.0, -2.0, 0.0, 1.0, 1.0];
let color = LinSrgb::new(0.2, 0.8, 0.4);
let mat3 = rgb_to_xyz_matrix::<encoding::Srgb, f64>();
let wp: Xyz<D65, f64> = D65::get_xyz();
let wp: Xyz<D65, f64> = D65::get_xyz().with_white_point();

group.bench_function("multiply_xyz", |b| {
b.iter(|| multiply_xyz::<D65, D50, _>(black_box(&inp1), black_box(&inp2)))
b.iter(|| multiply_xyz::<_>(black_box(&inp1), black_box(&inp2)))
});
group.bench_function("multiply_xyz_to_rgb", |b| {
b.iter(|| multiply_xyz_to_rgb::<encoding::Srgb, _>(black_box(&inp1), black_box(&wp)))
Expand Down
64 changes: 31 additions & 33 deletions palette/src/chromatic_adaptation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::convert::{FromColorUnclamped, IntoColorUnclamped};
use crate::float::Float;
use crate::from_f64;
use crate::matrix::{multiply_3x3, multiply_xyz, Mat3};
use crate::white_point::WhitePoint;
use crate::white_point::{Any, WhitePoint};
use crate::{FloatComponent, Xyz};

/// Chromatic adaptation methods implemented in the library
Expand All @@ -49,25 +49,25 @@ pub struct ConeResponseMatrices<T: Float> {
}

/// Generates a conversion matrix to convert the Xyz tristimulus values from
/// one illuminant to another (Swp -> Dwp)
pub trait TransformMatrix<Swp, Dwp, T>
/// one illuminant to another (`source_wp` to `destination_wp`)
pub trait TransformMatrix<T>
where
T: FloatComponent,
Swp: WhitePoint,
Dwp: WhitePoint,
{
/// Get the cone response functions for the chromatic adaptation method
fn get_cone_response(&self) -> ConeResponseMatrices<T>;

/// Generates a 3x3 transformation matrix to convert color from one
/// reference white point to another with the given cone_response
fn generate_transform_matrix(&self) -> Mat3<T> {
let s_wp: Xyz<Swp, T> = Swp::get_xyz();
let t_wp: Xyz<Dwp, T> = Dwp::get_xyz();
fn generate_transform_matrix(
&self,
source_wp: Xyz<Any, T>,
destination_wp: Xyz<Any, T>,
) -> Mat3<T> {
let adapt = self.get_cone_response();

let resp_src: Xyz<Swp, _> = multiply_xyz(&adapt.ma, &s_wp);
let resp_dst: Xyz<Dwp, _> = multiply_xyz(&adapt.ma, &t_wp);
let resp_src = multiply_xyz(&adapt.ma, &source_wp);
let resp_dst = multiply_xyz(&adapt.ma, &destination_wp);
let z = T::zero();
let resp = [
resp_dst.x / resp_src.x,
Expand All @@ -86,11 +86,9 @@ where
}
}

impl<Swp, Dwp, T> TransformMatrix<Swp, Dwp, T> for Method
impl<T> TransformMatrix<T> for Method
where
T: FloatComponent,
Swp: WhitePoint,
Dwp: WhitePoint,
{
#[rustfmt::skip]
fn get_cone_response(&self) -> ConeResponseMatrices<T> {
Expand Down Expand Up @@ -148,8 +146,8 @@ where
pub trait AdaptFrom<S, Swp, Dwp, T>: Sized
where
T: FloatComponent,
Swp: WhitePoint,
Dwp: WhitePoint,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
{
/// Convert the source color to the destination color using the bradford
/// method by default
Expand All @@ -158,22 +156,22 @@ where
}
/// Convert the source color to the destination color using the specified
/// method
fn adapt_from_using<M: TransformMatrix<Swp, Dwp, T>>(color: S, method: M) -> Self;
fn adapt_from_using<M: TransformMatrix<T>>(color: S, method: M) -> Self;
}

impl<S, D, Swp, Dwp, T> AdaptFrom<S, Swp, Dwp, T> for D
where
T: FloatComponent,
Swp: WhitePoint,
Dwp: WhitePoint,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
S: IntoColorUnclamped<Xyz<Swp, T>>,
D: FromColorUnclamped<Xyz<Dwp, T>>,
{
fn adapt_from_using<M: TransformMatrix<Swp, Dwp, T>>(color: S, method: M) -> D {
let src_xyz: Xyz<Swp, T> = color.into_color_unclamped();
let transform_matrix = method.generate_transform_matrix();
let dst_xyz: Xyz<Dwp, T> = multiply_xyz(&transform_matrix, &src_xyz);
D::from_color_unclamped(dst_xyz)
fn adapt_from_using<M: TransformMatrix<T>>(color: S, method: M) -> D {
let src_xyz = color.into_color_unclamped().with_white_point();
let transform_matrix = method.generate_transform_matrix(Swp::get_xyz(), Dwp::get_xyz());
let dst_xyz = multiply_xyz(&transform_matrix, &src_xyz);
D::from_color_unclamped(dst_xyz.with_white_point())
}
}

Expand All @@ -184,8 +182,8 @@ where
pub trait AdaptInto<D, Swp, Dwp, T>: Sized
where
T: FloatComponent,
Swp: WhitePoint,
Dwp: WhitePoint,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
{
/// Convert the source color to the destination color using the bradford
/// method by default
Expand All @@ -194,25 +192,25 @@ where
}
/// Convert the source color to the destination color using the specified
/// method
fn adapt_into_using<M: TransformMatrix<Swp, Dwp, T>>(self, method: M) -> D;
fn adapt_into_using<M: TransformMatrix<T>>(self, method: M) -> D;
}

impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for S
where
T: FloatComponent,
Swp: WhitePoint,
Dwp: WhitePoint,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
{
fn adapt_into_using<M: TransformMatrix<Swp, Dwp, T>>(self, method: M) -> D {
fn adapt_into_using<M: TransformMatrix<T>>(self, method: M) -> D {
D::adapt_from_using(self, method)
}
}

#[cfg(test)]
mod test {
use super::{AdaptFrom, AdaptInto, Method, TransformMatrix};
use crate::white_point::{A, C, D50, D65};
use crate::white_point::{WhitePoint, A, C, D50, D65};
use crate::Xyz;

#[test]
Expand All @@ -222,7 +220,7 @@ mod test {
0.7578869,
];
let xyz_scaling = Method::XyzScaling;
let computed = <dyn TransformMatrix<D65, D50, _>>::generate_transform_matrix(&xyz_scaling);
let computed = xyz_scaling.generate_transform_matrix(D65::get_xyz(), D50::get_xyz());
for (e, c) in expected.iter().zip(computed.iter()) {
assert_relative_eq!(e, c, epsilon = 0.0001)
}
Expand All @@ -234,7 +232,7 @@ mod test {
0.0000000, 0.7578869,
];
let von_kries = Method::VonKries;
let computed = <dyn TransformMatrix<D65, D50, _>>::generate_transform_matrix(&von_kries);
let computed = von_kries.generate_transform_matrix(D65::get_xyz(), D50::get_xyz());
for (e, c) in expected.iter().zip(computed.iter()) {
assert_relative_eq!(e, c, epsilon = 0.0001)
}
Expand All @@ -246,7 +244,7 @@ mod test {
0.0150436, 0.7521316,
];
let bradford = Method::Bradford;
let computed = <dyn TransformMatrix<D65, D50, _>>::generate_transform_matrix(&bradford);
let computed = bradford.generate_transform_matrix(D65::get_xyz(), D50::get_xyz());
for (e, c) in expected.iter().zip(computed.iter()) {
assert_relative_eq!(e, c, epsilon = 0.0001)
}
Expand Down
47 changes: 23 additions & 24 deletions palette/src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,19 @@
//! standard: std::marker::PhantomData<S>,
//! }
//!
//! # impl<S, T> FromColorUnclamped<Xyz<<S::Space as RgbSpace>::WhitePoint, T>> for ExampleType<S, T>
//! # impl<S, T> FromColorUnclamped<Xyz<<S::Space as RgbSpace<T>>::WhitePoint, T>> for ExampleType<S, T>
//! # where
//! # S: RgbStandard,
//! # S: RgbStandard<T>,
//! # T: FloatComponent
//! # {
//! # fn from_color_unclamped(color: Xyz<<S::Space as RgbSpace>::WhitePoint, T>) -> Self {
//! # fn from_color_unclamped(color: Xyz<<S::Space as RgbSpace<T>>::WhitePoint, T>) -> Self {
//! # ExampleType {alpha: T::max_intensity(), standard: std::marker::PhantomData}
//! # }
//! # }
//! #
//! # impl<S, T> FromColorUnclamped<ExampleType<S, T>> for Xyz<<S::Space as RgbSpace>::WhitePoint, T>
//! # impl<S, T> FromColorUnclamped<ExampleType<S, T>> for Xyz<<S::Space as RgbSpace<T>>::WhitePoint, T>
//! # where
//! # S: RgbStandard,
//! # S: RgbStandard<T>,
//! # T: FloatComponent
//! # {
//! # fn from_color_unclamped(color: ExampleType<S, T>) -> Self {
Expand Down Expand Up @@ -164,8 +164,8 @@
//! impl<S, T> FromColorUnclamped<Bgr<T>> for Rgb<S, T>
//! where
//! T: FloatComponent,
//! S: RgbStandard,
//! S::Space: RgbSpace<WhitePoint = D65>
//! S: RgbStandard<T>,
//! S::Space: RgbSpace<T, WhitePoint = D65>
//! {
//! fn from_color_unclamped(color: Bgr<T>) -> Rgb<S, T> {
//! Srgb::new(color.red, color.green, color.blue)
Expand All @@ -176,8 +176,8 @@
//! impl<S, T> FromColorUnclamped<Rgb<S, T>> for Bgr<T>
//! where
//! T: FloatComponent,
//! S: RgbStandard,
//! S::Space: RgbSpace<WhitePoint = D65>
//! S: RgbStandard<T>,
//! S::Space: RgbSpace<T, WhitePoint = D65>
//! {
//! fn from_color_unclamped(color: Rgb<S, T>) -> Bgr<T> {
//! let color = Srgb::from_color_unclamped(color);
Expand Down Expand Up @@ -235,8 +235,8 @@
//! // the transparency for us.
//! impl<S> FromColorUnclamped<Rgb<S, f32>> for CssRgb
//! where
//! S: RgbStandard,
//! S::Space: RgbSpace<WhitePoint = D65>,
//! S: RgbStandard<f32>,
//! S::Space: RgbSpace<f32, WhitePoint = D65>,
//! {
//! fn from_color_unclamped(color: Rgb<S, f32>) -> CssRgb{
//! let srgb = Srgb::from_color_unclamped(color)
Expand All @@ -253,8 +253,8 @@
//!
//! impl<S> FromColorUnclamped<CssRgb> for Rgb<S, f32>
//! where
//! S: RgbStandard,
//! S::Space: RgbSpace<WhitePoint = D65>,
//! S: RgbStandard<f32>,
//! S::Space: RgbSpace<f32, WhitePoint = D65>,
//! {
//! fn from_color_unclamped(color: CssRgb) -> Rgb<S, f32>{
//! Srgb::new(color.red, color.green, color.blue)
Expand Down Expand Up @@ -537,23 +537,22 @@ mod tests {
#[derive(FromColorUnclamped, WithAlpha)]
#[palette(
skip_derives(Xyz, Luma),
white_point = "S::WhitePoint",
component = "f64",
rgb_standard = "Linear<S>",
palette_internal,
palette_internal_not_base_type
)]
struct WithXyz<S: RgbSpace>(PhantomData<S>);
struct WithXyz<S>(PhantomData<S>);

impl<S: RgbSpace> Clone for WithXyz<S> {
impl<S> Clone for WithXyz<S> {
fn clone(&self) -> Self {
*self
}
}

impl<S: RgbSpace> Copy for WithXyz<S> {}
impl<S> Copy for WithXyz<S> {}

impl<S: RgbSpace> Clamp for WithXyz<S> {
impl<S> Clamp for WithXyz<S> {
fn is_within_bounds(&self) -> bool {
true
}
Expand All @@ -567,35 +566,35 @@ mod tests {

impl<S1, S2> FromColorUnclamped<WithXyz<S2>> for WithXyz<S1>
where
S1: RgbSpace,
S2: RgbSpace<WhitePoint = S1::WhitePoint>,
S1: RgbSpace<f64>,
S2: RgbSpace<f64, WhitePoint = S1::WhitePoint>,
{
fn from_color_unclamped(_color: WithXyz<S2>) -> Self {
WithXyz(PhantomData)
}
}

impl<S: RgbSpace> FromColorUnclamped<Xyz<S::WhitePoint, f64>> for WithXyz<S> {
impl<S: RgbSpace<f64>> FromColorUnclamped<Xyz<S::WhitePoint, f64>> for WithXyz<S> {
fn from_color_unclamped(_color: Xyz<S::WhitePoint, f64>) -> Self {
WithXyz(PhantomData)
}
}

impl<S: RgbSpace> FromColorUnclamped<WithXyz<S>> for Xyz<S::WhitePoint, f64> {
impl<S: RgbSpace<f64>> FromColorUnclamped<WithXyz<S>> for Xyz<S::WhitePoint, f64> {
fn from_color_unclamped(_color: WithXyz<S>) -> Xyz<S::WhitePoint, f64> {
Xyz::new(0.0, 1.0, 0.0)
}
}

impl<Rs: RgbSpace, Ls: LumaStandard<WhitePoint = Rs::WhitePoint>>
impl<Rs: RgbSpace<f64>, Ls: LumaStandard<f64, WhitePoint = Rs::WhitePoint>>
FromColorUnclamped<Luma<Ls, f64>> for WithXyz<Rs>
{
fn from_color_unclamped(_color: Luma<Ls, f64>) -> Self {
WithXyz(PhantomData)
}
}

impl<Rs: RgbSpace, Ls: LumaStandard<WhitePoint = Rs::WhitePoint>>
impl<Rs: RgbSpace<f64>, Ls: LumaStandard<f64, WhitePoint = Rs::WhitePoint>>
FromColorUnclamped<WithXyz<Rs>> for Luma<Ls, f64>
{
fn from_color_unclamped(_color: WithXyz<Rs>) -> Self {
Expand Down
14 changes: 11 additions & 3 deletions palette/src/encoding/gamma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,20 @@ use crate::{from_f64, FromF64};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Gamma<S, N: Number = F2p2>(PhantomData<(S, N)>);

impl<S: RgbSpace, N: Number> RgbStandard for Gamma<S, N> {
type Space = S;
impl<T, Sp, N> RgbStandard<T> for Gamma<Sp, N>
where
Sp: RgbSpace<T>,
N: Number,
{
type Space = Sp;
type TransferFn = GammaFn<N>;
}

impl<Wp: WhitePoint, N: Number> LumaStandard for Gamma<Wp, N> {
impl<T, Wp, N> LumaStandard<T> for Gamma<Wp, N>
where
Wp: WhitePoint<T>,
N: Number,
{
type WhitePoint = Wp;
type TransferFn = GammaFn<N>;
}
Expand Down
12 changes: 9 additions & 3 deletions palette/src/encoding/linear.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@ use crate::white_point::WhitePoint;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Linear<S>(PhantomData<S>);

impl<S: RgbSpace> RgbStandard for Linear<S> {
type Space = S;
impl<T, Sp> RgbStandard<T> for Linear<Sp>
where
Sp: RgbSpace<T>,
{
type Space = Sp;
type TransferFn = LinearFn;
}

impl<Wp: WhitePoint> LumaStandard for Linear<Wp> {
impl<T, Wp> LumaStandard<T> for Linear<Wp>
where
Wp: WhitePoint<T>,
{
type WhitePoint = Wp;
type TransferFn = LinearFn;
}
Expand Down
Loading