1#![cfg(feature = "image")]
2use crate::render::{Canvas, Pixel};
3use crate::types::Color;
4
5use image::{ImageBuffer, Luma, LumaA, Primitive, Rgb, Rgba};
6
7macro_rules! impl_pixel_for_image_pixel {
8 ($p:ident<$s:ident>: $c:pat => $d:expr) => {
9 impl<$s> Pixel for $p<$s>
10 where
11 $s: Primitive + 'static,
12 $p<$s>: image::Pixel<Subpixel = $s>,
13 {
14 type Image = ImageBuffer<Self, Vec<$s>>;
15 type Canvas = (Self, Self::Image);
16
17 fn default_color(color: Color) -> Self {
18 match color.select($s::zero(), $s::max_value()) {
19 $c => $p($d),
20 }
21 }
22 }
23 };
24}
25
26impl_pixel_for_image_pixel! { Luma<S>: p => [p] }
27impl_pixel_for_image_pixel! { LumaA<S>: p => [p, S::max_value()] }
28impl_pixel_for_image_pixel! { Rgb<S>: p => [p, p, p] }
29impl_pixel_for_image_pixel! { Rgba<S>: p => [p, p, p, S::max_value()] }
30
31impl<P: image::Pixel + 'static> Canvas for (P, ImageBuffer<P, Vec<P::Subpixel>>) {
32 type Pixel = P;
33 type Image = ImageBuffer<P, Vec<P::Subpixel>>;
34
35 fn new(width: u32, height: u32, dark_pixel: P, light_pixel: P) -> Self {
36 (dark_pixel, ImageBuffer::from_pixel(width, height, light_pixel))
37 }
38
39 fn draw_dark_pixel(&mut self, x: u32, y: u32) {
40 self.1.put_pixel(x, y, self.0);
41 }
42
43 fn into_image(self) -> ImageBuffer<P, Vec<P::Subpixel>> {
44 self.1
45 }
46}
47
48#[cfg(test)]
49mod render_tests {
50 use crate::render::Renderer;
51 use crate::types::Color;
52 use image::{Luma, Rgba};
53
54 #[test]
55 fn test_render_luma8_unsized() {
56 let image = Renderer::<Luma<u8>>::new(
57 &[
58 Color::Light,
59 Color::Dark,
60 Color::Dark,
61 Color::Dark,
63 Color::Light,
64 Color::Light,
65 Color::Light,
67 Color::Dark,
68 Color::Light,
69 ],
70 3,
71 1,
72 )
73 .module_dimensions(1, 1)
74 .build();
75
76 #[rustfmt::skip]
77 let expected = [
78 255, 255, 255, 255, 255,
79 255, 255, 0, 0, 255,
80 255, 0, 255, 255, 255,
81 255, 255, 0, 255, 255,
82 255, 255, 255, 255, 255,
83 ];
84 assert_eq!(image.into_raw(), expected);
85 }
86
87 #[test]
88 fn test_render_rgba_unsized() {
89 let image = Renderer::<Rgba<u8>>::new(&[Color::Light, Color::Dark, Color::Dark, Color::Dark], 2, 1)
90 .module_dimensions(1, 1)
91 .build();
92
93 #[rustfmt::skip]
94 let expected: &[u8] = &[
95 255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255,
96 255,255,255,255, 255,255,255,255, 0, 0, 0,255, 255,255,255,255,
97 255,255,255,255, 0, 0, 0,255, 0, 0, 0,255, 255,255,255,255,
98 255,255,255,255, 255,255,255,255, 255,255,255,255, 255,255,255,255,
99 ];
100
101 assert_eq!(image.into_raw(), expected);
102 }
103
104 #[test]
105 fn test_render_resized_min() {
106 let image = Renderer::<Luma<u8>>::new(&[Color::Dark, Color::Light, Color::Light, Color::Dark], 2, 1)
107 .min_dimensions(10, 10)
108 .build();
109
110 #[rustfmt::skip]
111 let expected: &[u8] = &[
112 255,255,255, 255,255,255, 255,255,255, 255,255,255,
113 255,255,255, 255,255,255, 255,255,255, 255,255,255,
114 255,255,255, 255,255,255, 255,255,255, 255,255,255,
115
116 255,255,255, 0, 0, 0, 255,255,255, 255,255,255,
117 255,255,255, 0, 0, 0, 255,255,255, 255,255,255,
118 255,255,255, 0, 0, 0, 255,255,255, 255,255,255,
119
120 255,255,255, 255,255,255, 0, 0, 0, 255,255,255,
121 255,255,255, 255,255,255, 0, 0, 0, 255,255,255,
122 255,255,255, 255,255,255, 0, 0, 0, 255,255,255,
123
124 255,255,255, 255,255,255, 255,255,255, 255,255,255,
125 255,255,255, 255,255,255, 255,255,255, 255,255,255,
126 255,255,255, 255,255,255, 255,255,255, 255,255,255,
127 ];
128
129 assert_eq!(image.dimensions(), (12, 12));
130 assert_eq!(image.into_raw(), expected);
131 }
132
133 #[test]
134 fn test_render_resized_max() {
135 let image = Renderer::<Luma<u8>>::new(&[Color::Dark, Color::Light, Color::Light, Color::Dark], 2, 1)
136 .max_dimensions(10, 5)
137 .build();
138
139 #[rustfmt::skip]
140 let expected: &[u8] = &[
141 255,255, 255,255, 255,255, 255,255,
142
143 255,255, 0, 0, 255,255, 255,255,
144
145 255,255, 255,255, 0, 0, 255,255,
146
147 255,255, 255,255, 255,255, 255,255,
148 ];
149
150 assert_eq!(image.dimensions(), (8, 4));
151 assert_eq!(image.into_raw(), expected);
152 }
153}