Search code examples
rustcolors

How to iterate over the RGB wheel?


I can't find a library that implements some sort of RGB iterator that iterates from red (255-0-0) to yellow (255-255-0) to etc. Is it possible to implement it?

Its struct should implement Iterator<Item=(u8,u8,u8)> and perhaps, it contains max_iters to change its length.

Searching for functions/methods in libraries, I have not found any implementation of it


Solution

  • Those RGB components are separable cyclic triangle waves with different offsets clamped between 0 and 255. A little arithmetic gives us a relatively compact formula: use modulo to get cycles, absolute value gives us triangle wave, .min() and .max() clamps the value.

    struct Rainbow(isize);
    
    impl Rainbow {
        fn eval(&self, offset: isize) -> u8 {
            let x = 255 * 2 - ((self.0 + offset * 255) % (255 * 6) - 255 * 3).abs();
            x.min(255).max(0) as u8
        }
    }
    
    impl Iterator for Rainbow {
        type Item = (u8, u8, u8);
        fn next(&mut self) -> Option<Self::Item> {
            let rgb = (self.eval(3), self.eval(1), self.eval(5));
            self.0 += 1;
            Some(rgb)
        }
    }
    
    fn main() {
        for (r, g, b) in Rainbow(0).take(1024) {
            println!("({r}, {g}, {b})");
        }
    }
    

    Playground