Skip to main content

leaf_raster/
fit.rs

1//! Aspect-preserving containment, in pixels.
2
3/// The pixel box an image fits into: as wide as `max_w` allows but never
4/// upscaled past the source's own pixels, and as tall as that width makes it,
5/// capped at `max_h` (shrinking the width back to keep the aspect ratio).
6///
7/// In pixels on purpose: the terminal's non-square cells and a GUI's points are
8/// both a rounding step *after* this policy, so the frontends can share the
9/// sizing rule and differ only in the rounding.
10pub fn fit_within(intrinsic: (u32, u32), max_w: u32, max_h: u32) -> (u32, u32) {
11    let (iw, ih) = (intrinsic.0.max(1) as u64, intrinsic.1.max(1) as u64);
12
13    // Fit the width, never upscaling; the height follows from the aspect ratio.
14    let mut w = iw.min(max_w.max(1) as u64);
15    let mut h = w * ih / iw;
16    let max_h = max_h.max(1) as u64;
17    if h > max_h {
18        h = max_h;
19        w = h * iw / ih;
20    }
21    (w.max(1) as u32, h.max(1) as u32)
22}
23
24#[cfg(test)]
25mod tests {
26    use super::*;
27
28    #[test]
29    fn a_small_image_is_never_upscaled() {
30        assert_eq!(fit_within((200, 100), 400, 600), (200, 100));
31    }
32
33    #[test]
34    fn a_wide_image_scales_down_to_the_width() {
35        assert_eq!(fit_within((800, 400), 400, 600), (400, 200));
36    }
37
38    #[test]
39    fn the_height_cap_shrinks_the_width_with_it() {
40        let (w, h) = fit_within((100, 4000), 400, 160);
41        assert_eq!(h, 160, "height is held to the cap");
42        assert_eq!(w, 4, "width shrinks to keep the aspect ratio");
43    }
44
45    #[test]
46    fn degenerate_inputs_still_yield_a_paintable_box() {
47        assert_eq!(fit_within((0, 0), 0, 0), (1, 1));
48        // An extreme aspect ratio can't round a side down to nothing.
49        let (w, h) = fit_within((10_000, 1), 100, 100);
50        assert!(w >= 1 && h >= 1);
51    }
52}