1use crate::definitions::Image;
2use crate::drawing::line::draw_line_segment_mut;
3use crate::drawing::Canvas;
4use crate::rect::Rect;
5use image::{GenericImage, ImageBuffer};
6use std::f32;
7
8#[must_use = "the function does not modify the original image"]
12pub fn draw_hollow_rect<I>(image: &I, rect: Rect, color: I::Pixel) -> Image<I::Pixel>
13where
14 I: GenericImage,
15{
16 let mut out = ImageBuffer::new(image.width(), image.height());
17 out.copy_from(image, 0, 0).unwrap();
18 draw_hollow_rect_mut(&mut out, rect, color);
19 out
20}
21
22pub fn draw_hollow_rect_mut<C>(canvas: &mut C, rect: Rect, color: C::Pixel)
26where
27 C: Canvas,
28{
29 let left = rect.left() as f32;
30 let right = rect.right() as f32;
31 let top = rect.top() as f32;
32 let bottom = rect.bottom() as f32;
33
34 draw_line_segment_mut(canvas, (left, top), (right, top), color);
35 draw_line_segment_mut(canvas, (left, bottom), (right, bottom), color);
36 draw_line_segment_mut(canvas, (left, top), (left, bottom), color);
37 draw_line_segment_mut(canvas, (right, top), (right, bottom), color);
38}
39
40#[must_use = "the function does not modify the original image"]
44pub fn draw_filled_rect<I>(image: &I, rect: Rect, color: I::Pixel) -> Image<I::Pixel>
45where
46 I: GenericImage,
47{
48 let mut out = ImageBuffer::new(image.width(), image.height());
49 out.copy_from(image, 0, 0).unwrap();
50 draw_filled_rect_mut(&mut out, rect, color);
51 out
52}
53
54pub fn draw_filled_rect_mut<C>(canvas: &mut C, rect: Rect, color: C::Pixel)
58where
59 C: Canvas,
60{
61 let canvas_bounds = Rect::at(0, 0).of_size(canvas.width(), canvas.height());
62 if let Some(intersection) = canvas_bounds.intersect(rect) {
63 for dy in 0..intersection.height() {
64 for dx in 0..intersection.width() {
65 let x = intersection.left() as u32 + dx;
66 let y = intersection.top() as u32 + dy;
67 canvas.draw_pixel(x, y, color);
68 }
69 }
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use crate::drawing::Blend;
77 use crate::rect::Rect;
78 use image::{GrayImage, Luma, Pixel, Rgb, RgbImage, Rgba, RgbaImage};
79 use test::{black_box, Bencher};
80
81 #[bench]
82 fn bench_draw_filled_rect_mut_rgb(b: &mut Bencher) {
83 let mut image = RgbImage::new(200, 200);
84 let color = Rgb([120u8, 60u8, 47u8]);
85 let rect = Rect::at(50, 50).of_size(80, 90);
86 b.iter(|| {
87 draw_filled_rect_mut(&mut image, rect, color);
88 black_box(&image);
89 });
90 }
91
92 #[test]
93 fn test_draw_hollow_rect() {
94 let image = GrayImage::from_pixel(5, 5, Luma([1u8]));
95
96 let expected = gray_image!(
97 1, 1, 1, 1, 1;
98 1, 1, 1, 1, 1;
99 1, 1, 4, 4, 4;
100 1, 1, 4, 1, 4;
101 1, 1, 4, 4, 4);
102
103 let actual = draw_hollow_rect(&image, Rect::at(2, 2).of_size(3, 3), Luma([4u8]));
104 assert_pixels_eq!(actual, expected);
105 }
106
107 #[test]
108 fn test_draw_filled_rect() {
109 let image = GrayImage::from_pixel(5, 5, Luma([1u8]));
110
111 let expected = gray_image!(
112 1, 1, 1, 1, 1;
113 1, 4, 4, 4, 1;
114 1, 4, 4, 4, 1;
115 1, 4, 4, 4, 1;
116 1, 1, 1, 1, 1);
117
118 let actual = draw_filled_rect(&image, Rect::at(1, 1).of_size(3, 3), Luma([4u8]));
119 assert_pixels_eq!(actual, expected);
120 }
121
122 #[test]
123 fn test_draw_blended_filled_rect() {
124 let white = Rgba([255u8, 255u8, 255u8, 255u8]);
127 let blue = Rgba([0u8, 0u8, 255u8, 255u8]);
128 let semi_transparent_red = Rgba([255u8, 0u8, 0u8, 127u8]);
129
130 let mut image = Blend(RgbaImage::from_pixel(5, 5, white));
131
132 draw_filled_rect_mut(&mut image, Rect::at(1, 1).of_size(3, 3), blue);
133 draw_filled_rect_mut(
134 &mut image,
135 Rect::at(2, 2).of_size(1, 1),
136 semi_transparent_red,
137 );
138
139 let mut blended = blue;
141 blended.blend(&semi_transparent_red);
142
143 #[rustfmt::skip]
144 let expected = vec![
145 white, white, white, white, white,
146 white, blue, blue, blue, white,
147 white, blue, blended, blue, white,
148 white, blue, blue, blue, white,
149 white, white, white, white, white
150 ];
151 let expected = RgbaImage::from_fn(5, 5, |x, y| expected[(y * 5 + x) as usize]);
152
153 assert_pixels_eq!(image.0, expected);
154
155 draw_filled_rect_mut(&mut image, Rect::at(2, 2).of_size(1, 1), blue);
158 assert_eq!(*image.0.get_pixel(2, 2), blue);
159 }
160}