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     let intermediate = std::cmp::max(1, intermediate);
49     if use_width {
50         if intermediate <= u64::from(::std::u32::MAX) {
51             (nwidth, intermediate as u32)
52         } else {
53             (
54                 (u64::from(nwidth) * u64::from(::std::u32::MAX) / intermediate) as u32,
55                 ::std::u32::MAX,
56             )
57         }
58     } else if intermediate <= u64::from(::std::u32::MAX) {
59         (intermediate as u32, nheight)
60     } else {
61         (
62             ::std::u32::MAX,
63             (u64::from(nheight) * u64::from(::std::u32::MAX) / intermediate) as u32,
64         )
65     }
66 }
67 
68 #[cfg(test)]
69 mod test {
70     quickcheck! {
71         fn resize_bounds_correctly_width(old_w: u32, new_w: u32) -> bool {
72             if old_w == 0 || new_w == 0 { return true; }
73             let result = super::resize_dimensions(old_w, 400, new_w, ::std::u32::MAX, false);
74             result.0 == new_w && result.1 == (400 as f64 * new_w as f64 / old_w as f64) as u32
75         }
76     }
77 
78     quickcheck! {
79         fn resize_bounds_correctly_height(old_h: u32, new_h: u32) -> bool {
80             if old_h == 0 || new_h == 0 { return true; }
81             let result = super::resize_dimensions(400, old_h, ::std::u32::MAX, new_h, false);
82             result.1 == new_h && result.0 == (400 as f64 * new_h as f64 / old_h as f64) as u32
83         }
84     }
85 
86     #[test]
resize_handles_fill()87     fn resize_handles_fill() {
88         let result = super::resize_dimensions(100, 200, 200, 500, true);
89         assert!(result.0 == 250);
90         assert!(result.1 == 500);
91 
92         let result = super::resize_dimensions(200, 100, 500, 200, true);
93         assert!(result.0 == 500);
94         assert!(result.1 == 250);
95     }
96 
97     #[test]
resize_never_rounds_to_zero()98     fn resize_never_rounds_to_zero() {
99         let result = super::resize_dimensions(1, 150, 128, 128, false);
100         assert!(result.0 > 0);
101         assert!(result.1 > 0);
102     }
103 
104     #[test]
resize_handles_overflow()105     fn resize_handles_overflow() {
106         let result = super::resize_dimensions(100, ::std::u32::MAX, 200, ::std::u32::MAX, true);
107         assert!(result.0 == 100);
108         assert!(result.1 == ::std::u32::MAX);
109 
110         let result = super::resize_dimensions(::std::u32::MAX, 100, ::std::u32::MAX, 200, true);
111         assert!(result.0 == ::std::u32::MAX);
112         assert!(result.1 == 100);
113     }
114 }
115