Skip to main content

white_balancer/math/
scale.rs

1use std::ops::{Div, Mul};
2
3pub trait ToFromu8 {
4    fn to_u8(self) -> u8;
5    fn from_u8(v: u8) -> Self;
6    fn from_f32(v: f32) -> Self;
7}
8
9macro_rules! impl_to_from_u8 {
10    ($($ty:ty)*) => {
11        $(
12            impl ToFromu8 for $ty {
13                #[inline]
14                fn to_u8(self) -> u8 {
15                    if self > Self::from(u8::max_value()) {
16                        u8::max_value()
17                    } else {
18                        self as u8
19                    }
20                }
21                #[inline]
22                fn from_u8(v: u8) -> $ty {
23                    v as $ty
24                }
25                #[inline]
26                fn from_f32(v: f32) -> $ty {
27                    v as $ty
28                }
29            }
30        )*
31    }
32}
33
34impl_to_from_u8!(f32 f64);
35
36#[inline]
37pub fn scale_pixel<T: ToFromu8>(pixel: u8, numerator: T, denominator: T) -> u8
38        where T: Clone + Mul<T, Output = T> + Div<T, Output = T>{
39    let res = T::from_u8(pixel) * numerator / denominator;
40    res.to_u8()
41}
42
43#[cfg(test)]
44mod test {
45    use super::*;
46
47    #[test]
48    fn test_normal_scaling() {
49        assert_eq!(scale_pixel(10u8, 2f32, 1f32), 20u8);
50        assert_eq!(scale_pixel(10u8, 1f32, 2f32), 5u8);
51        assert_eq!(scale_pixel(10u8, 2f64, 1f64), 20u8);
52        assert_eq!(scale_pixel(10u8, 1f64, 2f64), 5u8);
53    }
54
55    #[test]
56    fn test_overflow() {
57        let new_pixel = scale_pixel(250, 2f32, 1f32);
58        assert_eq!(new_pixel, 255u8);
59    }
60}