yuvutils_rs/sharpyuv/
sharp_gamma.rs

1/*
2 * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1.  Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * 2.  Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * 3.  Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29#![forbid(unsafe_code)]
30#[inline]
31/// Linear transfer function for sRGB
32pub(crate) fn srgb_to_linear(gamma: f32) -> f32 {
33    if gamma < 0f32 {
34        0f32
35    } else if gamma < 12.92f32 * 0.003_041_282_5_f32 {
36        gamma * (1f32 / 12.92f32)
37    } else if gamma < 1.0f32 {
38        ((gamma + 0.055_010_717_f32) / 1.055_010_7_f32).powf(2.4f32)
39    } else {
40        1.0f32
41    }
42}
43
44#[inline]
45/// Gamma transfer function for sRGB
46pub(crate) fn srgb_from_linear(linear: f32) -> f32 {
47    if linear < 0.0f32 {
48        0.0f32
49    } else if linear < 0.003_041_282_5_f32 {
50        linear * 12.92f32
51    } else if linear < 1.0f32 {
52        1.055_010_7_f32 * linear.powf(1.0f32 / 2.4f32) - 0.055_010_717_f32
53    } else {
54        1.0f32
55    }
56}
57
58#[inline]
59/// Linear transfer function for Rec.709
60pub(crate) fn rec709_to_linear(gamma: f32) -> f32 {
61    if gamma < 0.0f32 {
62        0.0f32
63    } else if gamma < 4.5f32 * 0.018_053_97_f32 {
64        gamma * (1f32 / 4.5f32)
65    } else if gamma < 1.0f32 {
66        ((gamma + 0.099_296_82_f32) / 1.099_296_8_f32).powf(1.0f32 / 0.45f32)
67    } else {
68        1.0f32
69    }
70}
71
72#[inline]
73/// Gamma transfer function for Rec.709
74pub(crate) fn rec709_from_linear(linear: f32) -> f32 {
75    if linear < 0.0f32 {
76        0.0f32
77    } else if linear < 0.018_053_97_f32 {
78        linear * 4.5f32
79    } else if linear < 1.0f32 {
80        1.099_296_8_f32 * linear.powf(0.45f32) - 0.099_296_82_f32
81    } else {
82        1.0f32
83    }
84}
85
86#[inline(always)]
87/// Pure gamma transfer function for gamma 2.2
88pub(crate) fn pure_gamma_function(x: f32, gamma: f32) -> f32 {
89    if x <= 0f32 {
90        0f32
91    } else if x >= 1f32 {
92        return 1f32;
93    } else {
94        return x.powf(gamma);
95    }
96}
97
98#[inline]
99/// Pure gamma transfer function for gamma 2.2
100pub(crate) fn gamma2p2_from_linear(linear: f32) -> f32 {
101    pure_gamma_function(linear, 1f32 / 2.2f32)
102}
103
104#[inline]
105/// Linear transfer function for gamma 2.2
106pub(crate) fn gamma2p2_to_linear(gamma: f32) -> f32 {
107    pure_gamma_function(gamma, 2.2f32)
108}
109
110#[inline]
111/// Pure gamma transfer function for gamma 2.8
112pub(crate) fn gamma2p8_from_linear(linear: f32) -> f32 {
113    pure_gamma_function(linear, 1f32 / 2.8f32)
114}
115
116#[inline]
117/// Linear transfer function for gamma 2.8
118pub(crate) fn gamma2p8_to_linear(gamma: f32) -> f32 {
119    pure_gamma_function(gamma, 2.8f32)
120}
121
122#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
123/// Declares transfer function for transfer components into a linear colorspace and its inverse
124pub enum SharpYuvGammaTransfer {
125    /// sRGB Transfer function
126    Srgb,
127    /// Rec.709 Transfer function
128    Rec709,
129    /// Pure gamma 2.2 Transfer function
130    Gamma2p2,
131    /// Pure gamma 2.8 Transfer function
132    Gamma2p8,
133}
134
135impl From<u8> for SharpYuvGammaTransfer {
136    fn from(value: u8) -> Self {
137        match value {
138            0 => SharpYuvGammaTransfer::Srgb,
139            1 => SharpYuvGammaTransfer::Rec709,
140            2 => SharpYuvGammaTransfer::Gamma2p2,
141            3 => SharpYuvGammaTransfer::Gamma2p8,
142            _ => SharpYuvGammaTransfer::Srgb,
143        }
144    }
145}
146
147impl SharpYuvGammaTransfer {
148    #[inline]
149    pub fn linearize(&self, value: f32) -> f32 {
150        match self {
151            SharpYuvGammaTransfer::Srgb => srgb_to_linear(value),
152            SharpYuvGammaTransfer::Rec709 => rec709_to_linear(value),
153            SharpYuvGammaTransfer::Gamma2p2 => gamma2p2_to_linear(value),
154            SharpYuvGammaTransfer::Gamma2p8 => gamma2p8_to_linear(value),
155        }
156    }
157
158    #[inline]
159    pub fn gamma(&self, value: f32) -> f32 {
160        match self {
161            SharpYuvGammaTransfer::Srgb => srgb_from_linear(value),
162            SharpYuvGammaTransfer::Rec709 => rec709_from_linear(value),
163            SharpYuvGammaTransfer::Gamma2p2 => gamma2p2_from_linear(value),
164            SharpYuvGammaTransfer::Gamma2p8 => gamma2p8_from_linear(value),
165        }
166    }
167}