1 //! Shared mathematical utility functions.
2 
3 /// Cut value to be inside given range
4 ///
5 /// ```
6 /// use image::math::utils;
7 ///
8 /// assert_eq!(utils::clamp(-5, 0, 10),  0);
9 /// assert_eq!(utils::clamp( 6, 0, 10),  6);
10 /// assert_eq!(utils::clamp(15, 0, 10), 10);
11 /// ```
12 #[inline]
13 #[deprecated]
clamp<N>(a: N, min: N, max: N) -> N where N: PartialOrd,14 pub fn clamp<N>(a: N, min: N, max: N) -> N
15 where
16     N: PartialOrd,
17 {
18     if a < min {
19         return min;
20     }
21     if a > max {
22         return max;
23     }
24     a
25 }
26 
27 /// Calculates the width and height an image should be resized to.
28 /// This preserves aspect ratio, and based on the `fill` parameter
29 /// will either fill the dimensions to fit inside the smaller constraint
30 /// (will overflow the specified bounds on one axis to preserve
31 /// aspect ratio), or will shrink so that both dimensions are
32 /// completely contained with in the given `width` and `height`,
33 /// with empty space on one axis.
resize_dimensions(width: u32, height: u32, nwidth: u32, nheight: u32, fill: bool) -> (u32, u32)34 pub(crate) fn resize_dimensions(width: u32, height: u32, nwidth: u32, nheight: u32, fill: bool) -> (u32, u32) {
35     let ratio = u64::from(width) * u64::from(nheight);
36     let nratio = u64::from(nwidth) * u64::from(height);
37 
38     let use_width = if fill {
39         nratio > ratio
40     } else {
41         nratio <= ratio
42     };
43     let intermediate = if use_width {
44         u64::from(height) * u64::from(nwidth) / u64::from(width)
45     } else {
46         u64::from(width) * u64::from(nheight) / u64::from(height)
47     };
48     if use_width {
49         if intermediate <= u64::from(::std::u32::MAX) {
50             (nwidth, intermediate as u32)
51         } else {
52             (
53                 (u64::from(nwidth) * u64::from(::std::u32::MAX) / intermediate) as u32,
54                 ::std::u32::MAX,
55             )
56         }
57     } else if intermediate <= u64::from(::std::u32::MAX) {
58         (intermediate as u32, nheight)
59     } else {
60         (
61             ::std::u32::MAX,
62             (u64::from(nheight) * u64::from(::std::u32::MAX) / intermediate) as u32,
63         )
64     }
65 }
66 
67 #[cfg(test)]
68 mod test {
69     quickcheck! {
70         fn resize_bounds_correctly_width(old_w: u32, new_w: u32) -> bool {
71             if old_w == 0 || new_w == 0 { return true; }
72             let result = super::resize_dimensions(old_w, 400, new_w, ::std::u32::MAX, false);
73             result.0 == new_w && result.1 == (400 as f64 * new_w as f64 / old_w as f64) as u32
74         }
75     }
76 
77     quickcheck! {
78         fn resize_bounds_correctly_height(old_h: u32, new_h: u32) -> bool {
79             if old_h == 0 || new_h == 0 { return true; }
80             let result = super::resize_dimensions(400, old_h, ::std::u32::MAX, new_h, false);
81             result.1 == new_h && result.0 == (400 as f64 * new_h as f64 / old_h as f64) as u32
82         }
83     }
84 
85     #[test]
resize_handles_fill()86     fn resize_handles_fill() {
87         let result = super::resize_dimensions(100, 200, 200, 500, true);
88         assert!(result.0 == 250);
89         assert!(result.1 == 500);
90 
91         let result = super::resize_dimensions(200, 100, 500, 200, true);
92         assert!(result.0 == 500);
93         assert!(result.1 == 250);
94     }
95 
96     #[test]
resize_handles_overflow()97     fn resize_handles_overflow() {
98         let result = super::resize_dimensions(100, ::std::u32::MAX, 200, ::std::u32::MAX, true);
99         assert!(result.0 == 100);
100         assert!(result.1 == ::std::u32::MAX);
101 
102         let result = super::resize_dimensions(::std::u32::MAX, 100, ::std::u32::MAX, 200, true);
103         assert!(result.0 == ::std::u32::MAX);
104         assert!(result.1 == 100);
105     }
106 }
107