palette/encoding/
gamma.rs

1//! Gamma encoding.
2
3use core::{marker::PhantomData, ops::Div};
4
5use crate::{
6    luma::LumaStandard,
7    num::{One, Powf, Real},
8    rgb::{RgbSpace, RgbStandard},
9};
10
11use super::{FromLinear, IntoLinear};
12
13/// Gamma encoding.
14///
15/// Gamma encoding or gamma correction is used to transform the intensity
16/// values to either match a non-linear display, like CRT, or to prevent
17/// banding among the darker colors. `GammaRgb` represents a gamma corrected
18/// RGB color, where the intensities are encoded using the following power-law
19/// expression: _V<sup> γ</sup>_ (where _V_ is the intensity value an _γ_ is the
20/// encoding gamma).
21///
22/// The gamma value is stored as a simple type that represents an `f32`
23/// constant.
24#[derive(Copy, Clone, Debug, PartialEq, Eq)]
25pub struct Gamma<S, N: Number = F2p2>(PhantomData<(S, N)>);
26
27impl<Sp, N> RgbStandard for Gamma<Sp, N>
28where
29    Sp: RgbSpace,
30    N: Number,
31{
32    type Space = Sp;
33    type TransferFn = GammaFn<N>;
34}
35
36impl<Wp, N> LumaStandard for Gamma<Wp, N>
37where
38    N: Number,
39{
40    type WhitePoint = Wp;
41    type TransferFn = GammaFn<N>;
42}
43
44/// The transfer function for gamma encoded colors.
45///
46/// Conversion is performed using a single `powf(x, gamma)` and `powf(x, 1.0 /
47/// gamma)` call, for from and into linear respectively. This makes
48/// `GammaFn<F2p2>` usable as a slightly less expensive approximation of the
49/// [`Srgb`][super::Srgb] transfer function.
50///
51/// The gamma value is stored as a simple type that represents an `f32`
52/// constant.
53#[derive(Copy, Clone, Debug, PartialEq, Eq)]
54pub struct GammaFn<N: Number = F2p2>(PhantomData<N>);
55
56impl<T, N> IntoLinear<T, T> for GammaFn<N>
57where
58    T: Real + One + Powf + Div<Output = T>,
59    N: Number,
60{
61    #[inline]
62    fn into_linear(x: T) -> T {
63        x.powf(T::one() / T::from_f64(N::VALUE))
64    }
65}
66
67impl<T, N> FromLinear<T, T> for GammaFn<N>
68where
69    T: Real + Powf,
70    N: Number,
71{
72    #[inline]
73    fn from_linear(x: T) -> T {
74        x.powf(T::from_f64(N::VALUE))
75    }
76}
77
78/// A type level float constant.
79pub trait Number: 'static {
80    /// The represented number.
81    const VALUE: f64;
82}
83
84/// Represents `2.2f64`.
85#[derive(Copy, Clone, Debug, PartialEq, Eq)]
86pub struct F2p2;
87
88impl Number for F2p2 {
89    const VALUE: f64 = 2.2;
90}