1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum Transfer {
7 Linear,
8 Srgb,
9 A98Rgb,
10 ProphotoRgb,
11 Rec2020,
15}
16
17impl Transfer {
18 const REC2020_ALPHA: f64 = 1.09929682680944;
19 const REC2020_BETA: f64 = 0.018053968510807;
20
21 pub fn encode(self, linear: f64) -> f64 {
23 let abs = linear.abs();
24 match self {
25 Self::Linear => linear,
26 Self::Srgb => {
27 if abs <= 0.0031308 {
28 linear * 12.92
29 } else {
30 linear.signum() * (1.055 * abs.powf(1.0 / 2.4) - 0.055)
31 }
32 }
33 Self::A98Rgb => linear.signum() * abs.powf(256.0 / 563.0),
34 Self::ProphotoRgb => {
35 if abs >= 1.0 / 512.0 {
36 linear.signum() * abs.powf(1.0 / 1.8)
37 } else {
38 linear * 16.0
39 }
40 }
41 Self::Rec2020 => {
42 if cfg!(feature = "rec2020-bt1886") {
43 linear.signum() * abs.powf(1.0 / 2.4)
44 } else if abs >= Self::REC2020_BETA {
45 linear.signum() * (Self::REC2020_ALPHA * abs.powf(0.45) - (Self::REC2020_ALPHA - 1.0))
46 } else {
47 linear * 4.5
48 }
49 }
50 }
51 }
52
53 pub fn decode(self, encoded: f64) -> f64 {
55 let abs = encoded.abs();
56 match self {
57 Self::Linear => encoded,
58 Self::Srgb => {
59 if abs > 0.04045 {
60 encoded.signum() * ((abs + 0.055) / 1.055).powf(2.4)
61 } else {
62 encoded / 12.92
63 }
64 }
65 Self::A98Rgb => encoded.signum() * abs.powf(563.0 / 256.0),
66 Self::ProphotoRgb => {
67 if abs >= 16.0 / 512.0 {
68 encoded.signum() * abs.powf(1.8)
69 } else {
70 encoded / 16.0
71 }
72 }
73 Self::Rec2020 => {
74 if cfg!(feature = "rec2020-bt1886") {
75 encoded.signum() * abs.powf(2.4)
76 } else if abs >= Self::REC2020_BETA * 4.5 {
77 encoded.signum() * ((abs + (Self::REC2020_ALPHA - 1.0)) / Self::REC2020_ALPHA).powf(1.0 / 0.45)
78 } else {
79 encoded / 4.5
80 }
81 }
82 }
83 }
84
85 pub fn encode_all(self, linear: [f64; 3]) -> [f64; 3] {
87 [self.encode(linear[0]), self.encode(linear[1]), self.encode(linear[2])]
88 }
89
90 pub fn decode_all(self, encoded: [f64; 3]) -> [f64; 3] {
92 [self.decode(encoded[0]), self.decode(encoded[1]), self.decode(encoded[2])]
93 }
94}