yuvutils_rs/sharpyuv/
sharp_gamma.rs1#![forbid(unsafe_code)]
30#[inline]
31pub(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]
45pub(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]
59pub(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]
73pub(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)]
87pub(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]
99pub(crate) fn gamma2p2_from_linear(linear: f32) -> f32 {
101 pure_gamma_function(linear, 1f32 / 2.2f32)
102}
103
104#[inline]
105pub(crate) fn gamma2p2_to_linear(gamma: f32) -> f32 {
107 pure_gamma_function(gamma, 2.2f32)
108}
109
110#[inline]
111pub(crate) fn gamma2p8_from_linear(linear: f32) -> f32 {
113 pure_gamma_function(linear, 1f32 / 2.8f32)
114}
115
116#[inline]
117pub(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)]
123pub enum SharpYuvGammaTransfer {
125 Srgb,
127 Rec709,
129 Gamma2p2,
131 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}