select_color/
hue_saturation.rs

1
2//! Helper functions for hue and saturation selection
3
4use image::{
5    Rgba,
6    RgbaImage,
7};
8
9/// Selects color at coordinate in a rectangle show hue and saturation
10pub fn select(rect: [u32; 4], x: u32, y: u32) -> Rgba<u8> {
11    let inv_rect_width = 1.0_f64 / rect[2] as f64;
12    let half_inv_rect_height = 0.5_f64 / rect[3] as f64;
13    let inv60 = 1.0_f64 / 60.0_f64;
14    
15    let fx = (x - rect[0]) as f64 * inv_rect_width;
16    let hue = fx * 360.0_f64;
17    // Saturation is 0.5 * fy, so by halving the height we save operations.
18    let saturation = (y - rect[1]) as f64 * half_inv_rect_height;
19    let hi = (hue * inv60) as isize;
20    let f = hue * inv60 - hi as f64;
21    let hi = hi % 6;
22    let v = 255; // use white as color without saturation.
23    let p = (255.0 * (1.0 - saturation)) as u8;
24    let q = (255.0 * (1.0 - f * saturation)) as u8;
25    let t = (255.0 * (1.0 - (1.0 - f) * saturation)) as u8;
26    Rgba([
27        match hi {
28            0 | 1 => p,
29            2 => t,
30            3 | 4 => v,
31            _ => q
32        },
33        match hi {
34            0 => t,
35            1 | 2 => v,
36            3 => q,
37            _ => p
38        },
39        match hi {
40            1 => q,
41            2 | 3 => p,
42            4 => t,
43            _ => v
44        },
45        255
46    ])
47}
48
49/// Sets colors to hue/saturation image.
50/// White is used as color without saturation.
51/// This is at the top of the image,
52/// while saturated colors are at the bottom.
53pub fn fill_image(
54    image: &mut RgbaImage,
55    rect: [u32; 4]
56) {
57    let inv_rect_width = 1.0_f64 / rect[2] as f64;
58    let half_inv_rect_height = 0.5_f64 / rect[3] as f64;
59    let inv60 = 1.0_f64 / 60.0_f64;
60    for x in rect[0]..rect[0] + rect[2] {
61        for y in rect[1]..rect[1] + rect[3] {
62            let fx = (x - rect[0]) as f64 * inv_rect_width;
63            let hue = fx * 360.0_f64;
64            // Saturation is 0.5 * fy, so by halving the height we save operations.
65            let saturation = (y - rect[1]) as f64 * half_inv_rect_height;
66            let hi = (hue * inv60) as isize;
67            let f = hue * inv60 - hi as f64;
68            let hi = hi % 6;
69            let v = 255; // use white as color without saturation.
70            let p = (255.0 * (1.0 - saturation)) as u8;
71            let q = (255.0 * (1.0 - f * saturation)) as u8;
72            let t = (255.0 * (1.0 - (1.0 - f) * saturation)) as u8;
73            *image.get_pixel_mut(x, y) = Rgba([
74                match hi {
75                    0 | 1 => p,
76                    2 => t,
77                    3 | 4 => v,
78                    _ => q
79                },
80                match hi {
81                    0 => t,
82                    1 | 2 => v,
83                    3 => q,
84                    _ => p
85                },
86                match hi {
87                    1 => q,
88                    2 | 3 => p,
89                    4 => t,
90                    _ => v
91                },
92                255
93            ]);
94        }
95    }
96}