1use rgb::{Bgr, Grb, Rgb};
2use core::array;
3use core::ops::Index;
4
5#[cfg(feature="micromath")]
6use micromath::F32Ext;
7
8#[derive(Debug)]
9pub struct GammaCurve([u8; 256]);
10
11impl GammaCurve {
12 pub fn new(gamma: f32) -> Self {
13 Self(array::from_fn(|x| {
14 Self::gamma_for_value(x as u8, gamma)
15 }))
16 }
17
18 fn gamma_for_value(value: u8, gamma: f32) -> u8 {
19 ((value as f32 / 255f32).powf(gamma) * 255f32 + 0.5) as u8
20 }
21}
22
23impl Default for GammaCurve {
24 fn default() -> Self {
25 Self::new(1.0)
26 }
27}
28
29impl Index<usize> for GammaCurve {
30 type Output = u8;
31
32 fn index(&self, index: usize) -> &Self::Output {
33 &self.0[index]
34 }
35}
36
37pub trait WithGamma {
38 fn with_gamma(self, curve: &GammaCurve) -> Self;
39}
40
41impl WithGamma for Rgb<u8> {
42 fn with_gamma(self, curve: &GammaCurve)-> Self {
43 Rgb::new(curve[self.r as usize], curve[self.g as usize], curve[self.b as usize])
44 }
45}
46
47impl WithGamma for Grb<u8> {
48 fn with_gamma(self, curve: &GammaCurve) -> Self {
49 Grb::new_grb(curve[self.g as usize], curve[self.r as usize], curve[self.b as usize])
50 }
51}
52
53impl WithGamma for Bgr<u8> {
54 fn with_gamma(self, curve: &GammaCurve) -> Self {
55 Bgr::new_bgr(curve[self.b as usize], curve[self.g as usize], curve[self.r as usize])
56 }
57}
58
59impl<T: WithGamma + Copy, const SIZE: usize> WithGamma for [T; SIZE] {
60 fn with_gamma(self, curve: &GammaCurve) -> Self {
61 array::from_fn(|x| { self[x].with_gamma(curve) })
62 }
63}