Skip to content

Commit

Permalink
Replace the generic PartialCam16 with generated structs
Browse files Browse the repository at this point in the history
  • Loading branch information
Ogeon committed Apr 1, 2024
1 parent a178e16 commit 123de6f
Show file tree
Hide file tree
Showing 14 changed files with 1,075 additions and 1,066 deletions.
123 changes: 36 additions & 87 deletions palette/src/cam16/full.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ use crate::{
};

use super::{
BakedParameters, Cam16Chromaticity, Cam16Luminance, PartialCam16, WhitePointParameter,
math::{
chromaticity::{Cam16Chromaticity, ChromaticityType},
luminance::{Cam16Luminance, LuminanceType},
},
BakedParameters, WhitePointParameter,
};

/// CIE CAM16 with an alpha component. See the [`Cam16a` implementation in
/// `Alpha`](crate::Alpha#Cam16a).
/// CIE CAM16 with an alpha component.
///
/// See the [`Cam16a` implementation in `Alpha`](crate::Alpha#Cam16a).
pub type Cam16a<T> = Alpha<Cam16<T>, T>;

/// The CIE CAM16 color appearance model.
Expand All @@ -31,9 +36,9 @@ pub type Cam16a<T> = Alpha<Cam16<T>, T>;
/// are there to bridge the gap.
///
/// Not all attributes are used when converting _from_ CAM16, since they are
/// correlated and derived from each other. This library provides a separate
/// [`PartialCam16`][super::PartialCam16] to make it easier to correctly specify
/// a minimum attribute set.
/// correlated and derived from each other. This library also provides partial
/// versions of this struct, to make it easier to correctly specify a minimum
/// attribute set.
#[derive(Clone, Copy, Debug, WithAlpha, Default)]
#[palette(palette_internal, component = "T")]
#[repr(C)]
Expand Down Expand Up @@ -82,9 +87,9 @@ impl<T> Cam16<T> {
/// the provided viewing conditions.
///
/// This assumes that all of the correlated attributes are consistent, as
/// only some of them are actually used. You may want to use
/// [`PartialCam16`] for more control over which set of attributes that
/// should be.
/// only some of them are actually used. You may want to use one of the
/// partial CAM16 representations for more control over which set of
/// attributes that should be.
#[inline]
pub fn into_xyz<WpParam>(
self,
Expand All @@ -107,35 +112,12 @@ impl<T> Cam16<T> {
+ Clone,
T::Mask: LazySelect<Xyz<white_point::Any, T>>,
{
super::math::cam16_to_xyz(self.into(), parameters.into().inner).with_white_point()
}

/// Reconstruct a full set of CIE CAM16 attributes, using the original viewing conditions.
#[inline]
pub fn from_partial<WpParam, L, C>(
partial: PartialCam16<L, C, T>,
parameters: impl Into<BakedParameters<WpParam, T>>,
) -> Self
where
WpParam: WhitePointParameter<T>,
T: Real + Zero + Arithmetics + Sqrt + PartialCmp + Clone,
T::Mask: LazySelect<T> + Clone,
L: Cam16Luminance<T>,
C: Cam16Chromaticity<T>,
{
partial.into_full(parameters)
}

/// Create a partial set of CIE CAM16 attributes.
///
/// It's also possible to use `PartialCam16::from` or `Cam16::into`.
#[inline]
pub fn into_partial<L, C>(self) -> PartialCam16<L, C, T>
where
L: Cam16Luminance<T>,
C: Cam16Chromaticity<T>,
{
PartialCam16::from_full(self)
let partial = (
LuminanceType::from_cam16(self.lightness, self.brightness),
ChromaticityType::from_cam16(self.chroma, self.colorfulness, self.saturation),
self.hue,
);
super::math::cam16_to_xyz(partial, parameters.into().inner).with_white_point()
}
}

Expand Down Expand Up @@ -164,9 +146,9 @@ impl<T, A> Alpha<Cam16<T>, A> {
/// attributes, under the provided viewing conditions.
///
/// This assumes that all of the correlated attributes are consistent, as
/// only some of them are actually used. You may want to use
/// [`PartialCam16a`](crate::cam16::PartialCam16a) for more control over
/// which set of attributes that should be.
/// only some of them are actually used. You may want to use one of the
/// partial CAM16 representations for more control over which set of
/// attributes that should be.
#[inline]
pub fn into_xyz<WpParam>(
self,
Expand Down Expand Up @@ -196,45 +178,6 @@ impl<T, A> Alpha<Cam16<T>, A> {
alpha,
}
}

/// Reconstruct a full set of CIE CAM16 attributes with transparency, using
/// the original viewing conditions.
#[inline]
pub fn from_partial<WpParam, L, C>(
partial: Alpha<PartialCam16<L, C, T>, A>,
parameters: impl Into<BakedParameters<WpParam, T>>,
) -> Self
where
WpParam: WhitePointParameter<T>,
T: Real + Zero + Arithmetics + Sqrt + PartialCmp + Clone,
T::Mask: LazySelect<T> + Clone,
L: Cam16Luminance<T>,
C: Cam16Chromaticity<T>,
{
let Alpha { color, alpha } = partial;

Alpha {
color: Cam16::from_partial(color, parameters),
alpha,
}
}

/// Create a partial set of CIE CAM16 attributes with transparency.
///
/// It's also possible to use `PartialCam16a::from` or `Cam16a::into`.
#[inline]
pub fn into_partial<L, C>(self) -> Alpha<PartialCam16<L, C, T>, A>
where
L: Cam16Luminance<T>,
C: Cam16Chromaticity<T>,
{
let Alpha { color, alpha } = self;

Alpha {
color: PartialCam16::from_full(color),
alpha,
}
}
}

impl<T> GetHue for Cam16<T>
Expand Down Expand Up @@ -291,7 +234,10 @@ impl_eq_hue!(
#[cfg(feature = "approx")]
mod test {
use crate::{
cam16::{ChromaticityType, LuminanceType, Parameters, PartialCam16},
cam16::{
math::chromaticity::ChromaticityType, math::luminance::LuminanceType, BakedParameters,
Parameters,
},
convert::{FromColorUnclamped, IntoColorUnclamped},
Srgb,
};
Expand All @@ -301,7 +247,7 @@ mod test {
macro_rules! assert_cam16_to_rgb {
($cam16:expr, $rgb:expr, $($params:tt)*) => {
let cam16 = $cam16;
let parameters = Parameters::TEST_DEFAULTS;
let parameters = BakedParameters::from(Parameters::TEST_DEFAULTS);

let rgb: Srgb<f64> = cam16.into_xyz(parameters).into_color_unclamped();
assert_relative_eq!(rgb, $rgb, $($params)*);
Expand All @@ -318,13 +264,16 @@ mod test {

for luminance in luminances {
for chromaticity in chromaticities {
let partial = PartialCam16 {
hue: cam16.hue,
chromaticity,
let partial = (
luminance,
};
chromaticity,
cam16.hue,
);

let xyz = crate::cam16::math::cam16_to_xyz(partial, parameters.inner).with_white_point();

assert_relative_eq!(
Srgb::<f64>::from_color_unclamped(dbg!(partial).into_xyz(parameters)),
Srgb::<f64>::from_color_unclamped(xyz),
$rgb,
$($params)*
);
Expand Down
20 changes: 12 additions & 8 deletions palette/src/cam16/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use core::{
use crate::{
angle::{RealAngle, SignedAngle},
bool_mask::LazySelect,
cam16::LuminanceType,
clamp,
hues::Cam16Hue,
num::{
Expand All @@ -16,7 +15,12 @@ use crate::{
xyz::Xyz,
};

use super::{Cam16, ChromaticityType, DynPartialCam16, Parameters};
use super::{Cam16, Parameters};

use self::{chromaticity::ChromaticityType, luminance::LuminanceType};

pub(crate) mod chromaticity;
pub(crate) mod luminance;

// This module is originally based on https://observablehq.com/@jrus/cam16.
// https://rawpedia.rawtherapee.com/CIECAM02 is also informative.
Expand Down Expand Up @@ -113,7 +117,7 @@ where

#[inline]
pub(crate) fn cam16_to_xyz<T>(
cam16: DynPartialCam16<T>,
cam16: (LuminanceType<T>, ChromaticityType<T>, Cam16Hue<T>),
parameters: DependentParameters<T>,
) -> Xyz<white_point::Any, T>
where
Expand All @@ -133,7 +137,7 @@ where
T::Mask: LazySelect<Xyz<white_point::Any, T>>,
{
// Weird naming, but we just want to know if it's black or not here.
let is_black = match &cam16.luminance {
let is_black = match &cam16.0 {
LuminanceType::Lightness(lightness) => lightness.eq(&T::zero()),
LuminanceType::Brightness(brightness) => brightness.eq(&T::zero()),
};
Expand All @@ -146,7 +150,7 @@ where

// Assumes that lightness has been checked to be non-zero in `cam16_to_xyz`.
fn non_black_cam16_to_xyz<T>(
cam16: DynPartialCam16<T>,
cam16: (LuminanceType<T>, ChromaticityType<T>, Cam16Hue<T>),
parameters: DependentParameters<T>,
) -> Xyz<white_point::Any, T>
where
Expand All @@ -162,9 +166,9 @@ where
+ SignedAngle
+ Clone,
{
let h_rad = cam16.hue.into_radians();
let h_rad = cam16.2.into_radians();
let (sin_h, cos_h) = h_rad.clone().sin_cos();
let j_root = match cam16.luminance {
let j_root = match cam16.0 {
LuminanceType::Lightness(j) => lightness_to_j_root(j),
LuminanceType::Brightness(q) => brightness_to_j_root(
q,
Expand All @@ -173,7 +177,7 @@ where
parameters.f_l_4.clone(),
),
};
let alpha = match cam16.chromaticity {
let alpha = match cam16.1 {
ChromaticityType::Chroma(c) => c / &j_root,
ChromaticityType::Colorfulness(m) => colorfulness_to_chroma(m, parameters.f_l_4) / &j_root,
ChromaticityType::Saturation(s) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,18 @@ use crate::{

/// Common methods for types representing apparent chromatic intensity metrics
/// of CAM16.
pub trait Cam16Chromaticity<T> {
pub(crate) trait Cam16Chromaticity<T> {
/// Create `Self` from a CAM16 chromaticity attribute.
fn from_cam16(chroma: T, colorfulness: T, saturation: T) -> Self;

/// Convert `self` into a dynamically decided chromaticity attribute.
fn into_dynamic(self) -> ChromaticityType<T>;
}

/// One of the apparent chromatic intensity metrics of CAM16, to be used in
/// [`PartialCam16`](crate::cam16::PartialCam16).
///
/// Combined with the hue and one of [`LuminanceType`], it can describe a
/// complete color as [`PartialCam16`](crate::cam16::PartialCam16).
/// One the apparent chromatic intensity metrics of CAM16.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[non_exhaustive]
pub enum ChromaticityType<T> {
pub(crate) enum ChromaticityType<T> {
/// The [chroma](https://en.wikipedia.org/wiki/Colorfulness#Chroma) (C) of a
/// color.
#[doc(alias = "C")]
Expand Down Expand Up @@ -176,10 +172,10 @@ impl<T> From<Saturation<T>> for ChromaticityType<T> {
}

/// The [chroma](https://en.wikipedia.org/wiki/Colorfulness#Chroma) (C) of a
/// color, to be used in [`PartialCam16`](crate::cam16::PartialCam16).
/// color.
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
pub struct Chroma<T>(pub T);
pub(crate) struct Chroma<T>(pub T);

impl<T> Cam16Chromaticity<T> for Chroma<T> {
fn from_cam16(chroma: T, _colorfulness: T, _saturation: T) -> Self {
Expand Down Expand Up @@ -218,10 +214,10 @@ impl<T> From<T> for Chroma<T> {
impl_eq!(Chroma, [0]);

/// The [colorfulness](https://en.wikipedia.org/wiki/Colorfulness) (M) of a
/// color, to be used in [`PartialCam16`](crate::cam16::PartialCam16).
/// color.
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
pub struct Colorfulness<T>(pub T);
pub(crate) struct Colorfulness<T>(pub T);

impl<T> Cam16Chromaticity<T> for Colorfulness<T> {
fn from_cam16(_chroma: T, colorfulness: T, _saturation: T) -> Self {
Expand Down Expand Up @@ -260,10 +256,10 @@ impl<T> From<T> for Colorfulness<T> {
impl_eq!(Colorfulness, [0]);

/// The [saturation](https://en.wikipedia.org/wiki/Colorfulness#Saturation) (s)
/// of a color, to be used in [`PartialCam16`](crate::cam16::PartialCam16).
/// of a color.
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
pub struct Saturation<T>(pub T);
pub(crate) struct Saturation<T>(pub T);

impl<T> Cam16Chromaticity<T> for Saturation<T> {
fn from_cam16(_chroma: T, _colorfulness: T, saturation: T) -> Self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,18 @@ use crate::{
};

/// Common methods for types representing apparent luminance metrics of CAM16.
pub trait Cam16Luminance<T> {
pub(crate) trait Cam16Luminance<T> {
/// Create `Self` from a CAM16 luminance attribute.
fn from_cam16(lightness: T, brightness: T) -> Self;

/// Convert `self` into a dynamically decided luminance attribute.
fn into_dynamic(self) -> LuminanceType<T>;
}

/// One of the apparent luminance metrics of CAM16.
///
/// Combined with the hue and one of [`ChromaticityType`], it can describe a
/// complete color as [`PartialCam16`](crate::cam16::PartialCam16).
/// One the apparent luminance metrics of CAM16.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[non_exhaustive]
pub enum LuminanceType<T> {
pub(crate) enum LuminanceType<T> {
/// The [lightness](https://en.wikipedia.org/wiki/Lightness) (J) of a color.
#[doc(alias = "J")]
Lightness(T),
Expand Down Expand Up @@ -121,11 +118,10 @@ impl<T> From<Brightness<T>> for LuminanceType<T> {
}
}

/// The [lightness](https://en.wikipedia.org/wiki/Lightness) (J) of a color, to
/// be used in [`PartialCam16`](crate::cam16::PartialCam16).
/// The [lightness](https://en.wikipedia.org/wiki/Lightness) (J) of a color.
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
pub struct Lightness<T>(pub T);
pub(crate) struct Lightness<T>(pub T);

impl<T> Cam16Luminance<T> for Lightness<T> {
fn from_cam16(lightness: T, _brightness: T) -> Self {
Expand Down Expand Up @@ -163,11 +159,10 @@ impl<T> From<T> for Lightness<T> {

impl_eq!(Lightness, [0]);

/// The [brightness](https://en.wikipedia.org/wiki/Brightness) (Q) of a color,
/// to be used in [`PartialCam16`](crate::cam16::PartialCam16).
/// The [brightness](https://en.wikipedia.org/wiki/Brightness) (Q) of a color.
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
pub struct Brightness<T>(pub T);
pub(crate) struct Brightness<T>(pub T);

impl<T> Cam16Luminance<T> for Brightness<T> {
fn from_cam16(_lightness: T, brightness: T) -> Self {
Expand Down
Loading

0 comments on commit 123de6f

Please sign in to comment.