image_effects/
effect.rs

1use image::{ImageBuffer, Rgb, DynamicImage, Rgba, Frame};
2
3use crate::utils::{image::{RgbImageRepr, RgbPixelRepr, get_dimensions_of_matrix, RgbaImageRepr, RgbaPixelRepr}, numops::map_to_2d};
4
5/// Defines an effect that can be applied onto `T`.
6/// 
7/// Implementing this auto-implements `Affectable<T, F>` for `T`,
8/// where `F` is this effect.
9pub trait Effect<T> {
10    /// Affects `T` using `self`.
11    fn affect(&self, item: T) -> T;
12}
13
14/// Defines something that can be affected.
15/// 
16/// This is auto-implemented for any `T` and `F` where `F`
17/// is an effect that can be applied on `T`.
18/// 
19/// As a result it should almost never be implemented directly, like `Into<T>` in the
20/// standard library.
21pub trait Affectable<T, F: Effect<T>> {
22
23    /// Applies an effect on `self`.
24    fn apply(self, effect: &F) -> Self;
25}
26
27impl<T, F> Affectable<T, F> for T where F: Effect<T> {
28    fn apply(self, effect: &F) -> Self {
29        effect.affect(self)
30    }
31}
32
33impl<F> Effect<RgbaPixelRepr> for F where F: Effect<RgbPixelRepr> {
34    fn affect(&self, item: RgbaPixelRepr) -> RgbaPixelRepr {
35        let [r, g, b, a] = item;
36        let [r, g, b] = self.affect([r, g, b]);
37        [r, g, b, a]
38    }
39}
40
41impl<F> Effect<RgbImageRepr> for F where F: Effect<RgbPixelRepr> {
42    fn affect(&self, mut item: RgbImageRepr) -> RgbImageRepr {
43        for row in item.iter_mut() {
44            for pixel in row.iter_mut() {
45                *pixel = self.affect(*pixel);
46            }
47        }
48        item
49    }
50}
51
52impl<F> Effect<RgbaImageRepr> for F where F: Effect<RgbImageRepr> {
53    fn affect(&self, item: RgbaImageRepr) -> RgbaImageRepr {
54        let (xs, ys) = get_dimensions_of_matrix(&item);
55
56        let mut rgb_repr = vec![vec![[0_u8; 3]; xs]; ys];
57        let mut output = vec![vec![[0_u8; 4]; xs]; ys];
58
59        for y in 0..ys {
60            for x in 0..xs {
61                let [r, g, b, _] = item[y][x];
62                rgb_repr[y][x] = [r, g, b];
63            }
64        }
65
66        let rgb_repr = self.affect(rgb_repr);
67
68        for y in 0..ys {
69            for x in 0..xs {
70                let [r, g, b] = rgb_repr[y][x];
71                output[y][x] = [r, g, b, item[y][x][3]];
72            }
73        }
74
75        output
76    }
77}
78
79impl<F> Effect<ImageBuffer<Rgb<u8>, Vec<u8>>> for F where F: Effect<RgbImageRepr> {
80    fn affect(&self, item: ImageBuffer<Rgb<u8>, Vec<u8>>) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
81        let (xs, ys) = item.dimensions();
82        let (xs, ys) = (xs as usize, ys as usize);
83    
84        let mut img_matrix = vec![vec![[0_u8; 3]; xs]; ys];
85    
86        for (i, pixel) in item.pixels().into_iter().enumerate() {
87           let (x, y) = map_to_2d(i, xs);
88           img_matrix[y][x] = pixel.0;
89        }
90    
91        img_matrix = self.affect(img_matrix);
92
93        let (xdim, ydim) = get_dimensions_of_matrix(&img_matrix);
94    
95        ImageBuffer::from_fn(xdim as u32, ydim as u32, |x, y| {
96            image::Rgb(img_matrix[y as usize][x as usize])
97        })
98    }
99}
100
101impl<F> Effect<ImageBuffer<Rgba<u8>, Vec<u8>>> for F where F: Effect<RgbaImageRepr> {
102    fn affect(&self, item: ImageBuffer<Rgba<u8>, Vec<u8>>) -> ImageBuffer<Rgba<u8>, Vec<u8>> {
103        let (xs, ys) = item.dimensions();
104        let (xs, ys) = (xs as usize, ys as usize);
105    
106        let mut img_matrix = vec![vec![[0_u8; 4]; xs]; ys];
107    
108        for (i, pixel) in item.pixels().into_iter().enumerate() {
109           let (x, y) = map_to_2d(i, xs);
110           img_matrix[y][x] = pixel.0;
111        }
112    
113        img_matrix = self.affect(img_matrix);
114
115        let (xdim, ydim) = get_dimensions_of_matrix(&img_matrix);
116    
117        ImageBuffer::from_fn(xdim as u32, ydim as u32, |x, y| {
118            image::Rgba(img_matrix[y as usize][x as usize])
119        })
120    }
121}
122
123impl<F> Effect<DynamicImage> for F where F: 
124    Effect<ImageBuffer<Rgb<u8>, Vec<u8>>> 
125    + Effect<ImageBuffer<Rgba<u8>, Vec<u8>>>
126{
127    fn affect(&self, item: DynamicImage) -> DynamicImage {
128        match item {
129            DynamicImage::ImageRgb8(img) => {
130                DynamicImage::from(self.affect(img))
131            },
132            DynamicImage::ImageRgba8(img) => {
133                DynamicImage::from(self.affect(img))
134            },
135            _ => {
136                DynamicImage::ImageRgb8(self.affect(item.into_rgb8()))
137            }
138        }
139    }
140} 
141
142impl<F> Effect<Frame> for F where F: Effect<ImageBuffer<Rgba<u8>, Vec<u8>>> {
143    fn affect(&self, item: Frame) -> Frame {
144        let left = item.left();
145        let top = item.top();
146        let delay = item.delay();
147
148        let new_buf = self.affect(item.into_buffer());
149        Frame::from_parts(new_buf, left, top, delay)
150    }
151}