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