parallel_image/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
use std::path::Path;

use anyhow::Result;
use rayon::prelude::*;

pub struct RgbaImage {
    width: usize,
    height: usize,
    data: Box<[u8]>,
}

impl RgbaImage {
    pub fn new(width: usize, height: usize) -> Self {
        Self {
            width,
            height,
            data: vec![0; width * height * 4].into_boxed_slice(),
        }
    }

    pub fn fill_pixels(&mut self, op: impl Fn(usize, usize) -> (u8, u8, u8, u8) + Sync) {
        self.data
            .par_chunks_mut(4)
            .enumerate()
            .for_each(|(index, pixel)| {
                let x = index % self.width;
                let y = index / self.width;
                let (r, g, b, a) = op(x, y);
                pixel[0] = r;
                pixel[1] = g;
                pixel[2] = b;
                pixel[3] = a;
            });
    }

    pub fn save_webp(&self, path: impl AsRef<Path>) -> Result<()> {
        let encoded = webp_encoder::webp_encode_lossless_rgba(&self.data, self.width, self.height)?;
        std::fs::write(path, encoded.webp_file())?;
        Ok(())
    }
}