imageproc/
definitions.rs

1//! Trait definitions and type aliases.
2
3use image::{ImageBuffer, Luma, LumaA, Pixel, Rgb, Rgba};
4use std::{i16, u16, u8};
5
6/// An `ImageBuffer` containing Pixels of type P with storage `Vec<P::Subpixel>`.
7/// Most operations in this library only support inputs of type `Image`, rather
8/// than arbitrary `image::GenericImage`s. This is obviously less flexible, but
9/// has the advantage of allowing many functions to be more performant. We may want
10/// to add more flexibility later, but this should not be at the expense of performance.
11/// When specialisation lands we should be able to do this by defining traits for images
12/// with contiguous storage.
13pub type Image<P> = ImageBuffer<P, Vec<<P as Pixel>::Subpixel>>;
14
15/// Pixels which have a named Black value.
16pub trait HasBlack {
17    /// Returns a black pixel of this type.
18    fn black() -> Self;
19}
20
21/// Pixels which have a named White value.
22pub trait HasWhite {
23    /// Returns a white pixel of this type.
24    fn white() -> Self;
25}
26
27macro_rules! impl_black_white {
28    ($for_:ty, $min:expr, $max:expr) => {
29        impl HasBlack for $for_ {
30            fn black() -> Self {
31                $min
32            }
33        }
34
35        impl HasWhite for $for_ {
36            fn white() -> Self {
37                $max
38            }
39        }
40    };
41}
42
43impl_black_white!(Luma<u8>, Luma([u8::MIN]), Luma([u8::MAX]));
44impl_black_white!(Luma<u16>, Luma([u16::MIN]), Luma([u16::MAX]));
45impl_black_white!(
46    LumaA<u8>,
47    LumaA([u8::MIN, u8::MAX]),
48    LumaA([u8::MAX, u8::MAX])
49);
50impl_black_white!(
51    LumaA<u16>,
52    LumaA([u16::MIN, u16::MAX]),
53    LumaA([u16::MAX, u16::MAX])
54);
55impl_black_white!(Rgb<u8>, Rgb([u8::MIN; 3]), Rgb([u8::MAX; 3]));
56impl_black_white!(Rgb<u16>, Rgb([u16::MIN; 3]), Rgb([u16::MAX; 3]));
57impl_black_white!(
58    Rgba<u8>,
59    Rgba([u8::MIN, u8::MIN, u8::MIN, u8::MAX]),
60    Rgba([u8::MAX, u8::MAX, u8::MAX, u8::MAX])
61);
62impl_black_white!(
63    Rgba<u16>,
64    Rgba([u16::MIN, u16::MIN, u16::MIN, u16::MAX]),
65    Rgba([u16::MAX, u16::MAX, u16::MAX, u16::MAX])
66);
67
68/// Something with a 2d position.
69pub trait Position {
70    /// x-coordinate.
71    fn x(&self) -> u32;
72    /// y-coordinate.
73    fn y(&self) -> u32;
74}
75
76/// Something with a score.
77pub trait Score {
78    /// Score of this item.
79    fn score(&self) -> f32;
80}
81
82/// A type to which we can clamp a value of type T.
83/// Implementations are not required to handle `NaN`s gracefully.
84pub trait Clamp<T> {
85    /// Clamp `x` to a valid value for this type.
86    fn clamp(x: T) -> Self;
87}
88
89/// Creates an implementation of Clamp<From> for type To.
90macro_rules! implement_clamp {
91    ($from:ty, $to:ty, $min:expr, $max:expr, $min_from:expr, $max_from:expr) => {
92        impl Clamp<$from> for $to {
93            fn clamp(x: $from) -> $to {
94                if x < $max_from as $from {
95                    if x > $min_from as $from {
96                        x as $to
97                    } else {
98                        $min
99                    }
100                } else {
101                    $max
102                }
103            }
104        }
105    };
106}
107
108/// Implements Clamp<T> for T, for all input types T.
109macro_rules! implement_identity_clamp {
110    ( $($t:ty),* ) => {
111        $(
112            impl Clamp<$t> for $t {
113                fn clamp(x: $t) -> $t { x }
114            }
115        )*
116    };
117}
118
119implement_clamp!(i16, u8, u8::MIN, u8::MAX, u8::MIN as i16, u8::MAX as i16);
120implement_clamp!(u16, u8, u8::MIN, u8::MAX, u8::MIN as u16, u8::MAX as u16);
121implement_clamp!(i32, u8, u8::MIN, u8::MAX, u8::MIN as i32, u8::MAX as i32);
122implement_clamp!(u32, u8, u8::MIN, u8::MAX, u8::MIN as u32, u8::MAX as u32);
123implement_clamp!(f32, u8, u8::MIN, u8::MAX, u8::MIN as f32, u8::MAX as f32);
124implement_clamp!(f64, u8, u8::MIN, u8::MAX, u8::MIN as f64, u8::MAX as f64);
125
126implement_clamp!(
127    i32,
128    u16,
129    u16::MIN,
130    u16::MAX,
131    u16::MIN as i32,
132    u16::MAX as i32
133);
134implement_clamp!(
135    f32,
136    u16,
137    u16::MIN,
138    u16::MAX,
139    u16::MIN as f32,
140    u16::MAX as f32
141);
142implement_clamp!(
143    f64,
144    u16,
145    u16::MIN,
146    u16::MAX,
147    u16::MIN as f64,
148    u16::MAX as f64
149);
150
151implement_clamp!(
152    i32,
153    i16,
154    i16::MIN,
155    i16::MAX,
156    i16::MIN as i32,
157    i16::MAX as i32
158);
159
160implement_identity_clamp!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
161
162#[cfg(test)]
163mod tests {
164    use super::Clamp;
165
166    #[test]
167    fn test_clamp_f32_u8() {
168        let t: u8 = Clamp::clamp(255f32);
169        assert_eq!(t, 255u8);
170        let u: u8 = Clamp::clamp(300f32);
171        assert_eq!(u, 255u8);
172        let v: u8 = Clamp::clamp(0f32);
173        assert_eq!(v, 0u8);
174        let w: u8 = Clamp::clamp(-5f32);
175        assert_eq!(w, 0u8);
176    }
177
178    #[test]
179    fn test_clamp_f32_u16() {
180        let t: u16 = Clamp::clamp(65535f32);
181        assert_eq!(t, 65535u16);
182        let u: u16 = Clamp::clamp(300000f32);
183        assert_eq!(u, 65535u16);
184        let v: u16 = Clamp::clamp(0f32);
185        assert_eq!(v, 0u16);
186        let w: u16 = Clamp::clamp(-5f32);
187        assert_eq!(w, 0u16);
188    }
189}