From d6985379c5659d8d58c94bc77314312dfbc7d55d Mon Sep 17 00:00:00 2001 From: Jibago Date: Wed, 26 Mar 2025 12:21:20 +0900 Subject: [PATCH 1/5] Add masked canvas --- examples/masked.rs | 18 ++++++++++++++++++ src/drawing/canvas.rs | 32 +++++++++++++++++++++++++++++--- src/drawing/mod.rs | 2 +- 3 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 examples/masked.rs diff --git a/examples/masked.rs b/examples/masked.rs new file mode 100644 index 00000000..61630ce7 --- /dev/null +++ b/examples/masked.rs @@ -0,0 +1,18 @@ +use image::{ImageBuffer, Rgb}; +use imageproc::{drawing::{draw_filled_circle, draw_filled_rect_mut}, rect::Rect}; + +fn main() { + // Load the image + let image = ImageBuffer::, Vec<_>>::new(256, 256); + + // Create a mask + let mask = ImageBuffer::new(image.width(), image.height()); + let shorter_side = mask.width().min(mask.height()) as i32; + let center_x = mask.width() / 2; + let center_y = mask.height() / 2; + let mask = draw_filled_circle(&mask, (center_x as i32, center_y as i32), shorter_side / 4, image::Luma([255u8])); + + let mut canvas = imageproc::drawing::Masked { inner: image, mask }; + draw_filled_rect_mut(&mut canvas, Rect::at(0, 0).of_size(center_x, center_y), Rgb([255u8, 0u8, 0u8])); + canvas.inner.save("masked.png").unwrap(); +} \ No newline at end of file diff --git a/src/drawing/canvas.rs b/src/drawing/canvas.rs index 1fe764bd..627fb40b 100644 --- a/src/drawing/canvas.rs +++ b/src/drawing/canvas.rs @@ -1,4 +1,4 @@ -use image::{GenericImage, GenericImageView, Pixel}; +use image::{GenericImage, GenericImageView, Luma, Pixel}; /// A surface for drawing on - many drawing functions in this /// library are generic over a `Canvas` to allow the user to @@ -98,7 +98,7 @@ where /// for an example using this type. pub struct Blend(pub I); -impl Canvas for Blend { +impl Canvas for Blend { type Pixel = I::Pixel; fn dimensions(&self) -> (u32, u32) { @@ -112,6 +112,32 @@ impl Canvas for Blend { fn draw_pixel(&mut self, x: u32, y: u32, color: Self::Pixel) { let mut pix = self.0.get_pixel(x, y); pix.blend(&color); - self.0.put_pixel(x, y, pix); + self.0.draw_pixel(x, y, pix); + } +} + +/// +pub struct Masked{ + /// + pub inner: I, + /// + pub mask: M, +} + +impl>> Canvas for Masked { + type Pixel = I::Pixel; + + fn dimensions(&self) -> (u32, u32) { + self.inner.dimensions() + } + + fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel { + self.inner.get_pixel(x, y) + } + + fn draw_pixel(&mut self, x: u32, y: u32, color: Self::Pixel) { + if self.mask.get_pixel(x, y).0[0] != 0 { + self.inner.draw_pixel(x, y, color); + } } } diff --git a/src/drawing/mod.rs b/src/drawing/mod.rs index a56aa0fa..620212c2 100644 --- a/src/drawing/mod.rs +++ b/src/drawing/mod.rs @@ -4,7 +4,7 @@ mod bezier; pub use self::bezier::{draw_cubic_bezier_curve, draw_cubic_bezier_curve_mut}; mod canvas; -pub use self::canvas::{Blend, Canvas}; +pub use self::canvas::{Blend, Canvas, Masked}; mod conics; pub use self::conics::{ From ceb14259ac142ad7fcfe59f026dced1513466010 Mon Sep 17 00:00:00 2001 From: Jibago Date: Wed, 26 Mar 2025 13:16:03 +0900 Subject: [PATCH 2/5] into_image --- examples/masked.rs | 4 ++-- src/drawing/canvas.rs | 21 ++++++++++++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/examples/masked.rs b/examples/masked.rs index 61630ce7..41372d2d 100644 --- a/examples/masked.rs +++ b/examples/masked.rs @@ -1,5 +1,5 @@ -use image::{ImageBuffer, Rgb}; -use imageproc::{drawing::{draw_filled_circle, draw_filled_rect_mut}, rect::Rect}; +use image::{GenericImage, ImageBuffer, Rgb}; +use imageproc::{drawing::{draw_filled_circle, draw_filled_rect_mut, Canvas}, rect::Rect}; fn main() { // Load the image diff --git a/src/drawing/canvas.rs b/src/drawing/canvas.rs index 627fb40b..eb7e8f70 100644 --- a/src/drawing/canvas.rs +++ b/src/drawing/canvas.rs @@ -71,6 +71,9 @@ pub trait Canvas { /// should be within `dimensions` - if not then panicking /// is a valid implementation behaviour. fn draw_pixel(&mut self, x: u32, y: u32, color: Self::Pixel); + + /// Consumes the canvas and returns the underlying image. + fn into_image(self) -> impl GenericImage; } impl Canvas for I @@ -90,6 +93,10 @@ where fn draw_pixel(&mut self, x: u32, y: u32, color: Self::Pixel) { self.put_pixel(x, y, color) } + + fn into_image(self) -> impl GenericImage { + self + } } /// A canvas that blends pixels when drawing. @@ -114,13 +121,17 @@ impl Canvas for Blend { pix.blend(&color); self.0.draw_pixel(x, y, pix); } + + fn into_image(self) -> impl GenericImage { + self.0.into_image() + } } -/// +/// A canvas that only draws pixels where a mask is non-zero. pub struct Masked{ - /// + /// A canvas to draw on. pub inner: I, - /// + /// A mask image where non-zero pixels allow drawing. pub mask: M, } @@ -140,4 +151,8 @@ impl>> Canvas for Masked { self.inner.draw_pixel(x, y, color); } } + + fn into_image(self) -> impl GenericImage { + self.inner.into_image() + } } From 591f38d3b05a578cadc624c6b095b37ab23bf125 Mon Sep 17 00:00:00 2001 From: Jibago Date: Wed, 26 Mar 2025 13:25:27 +0900 Subject: [PATCH 3/5] Added constructor --- examples/masked.rs | 6 +++--- src/drawing/canvas.rs | 13 ++++++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/examples/masked.rs b/examples/masked.rs index 41372d2d..c118a41c 100644 --- a/examples/masked.rs +++ b/examples/masked.rs @@ -1,5 +1,5 @@ -use image::{GenericImage, ImageBuffer, Rgb}; -use imageproc::{drawing::{draw_filled_circle, draw_filled_rect_mut, Canvas}, rect::Rect}; +use image::{ImageBuffer, Rgb}; +use imageproc::{drawing::{draw_filled_circle, draw_filled_rect_mut}, rect::Rect}; fn main() { // Load the image @@ -12,7 +12,7 @@ fn main() { let center_y = mask.height() / 2; let mask = draw_filled_circle(&mask, (center_x as i32, center_y as i32), shorter_side / 4, image::Luma([255u8])); - let mut canvas = imageproc::drawing::Masked { inner: image, mask }; + let mut canvas = imageproc::drawing::Masked::new(image, mask); draw_filled_rect_mut(&mut canvas, Rect::at(0, 0).of_size(center_x, center_y), Rgb([255u8, 0u8, 0u8])); canvas.inner.save("masked.png").unwrap(); } \ No newline at end of file diff --git a/src/drawing/canvas.rs b/src/drawing/canvas.rs index eb7e8f70..bb1037fe 100644 --- a/src/drawing/canvas.rs +++ b/src/drawing/canvas.rs @@ -132,7 +132,18 @@ pub struct Masked{ /// A canvas to draw on. pub inner: I, /// A mask image where non-zero pixels allow drawing. - pub mask: M, + mask: M, +} + +impl Masked { + /// Create a new masked canvas. + /// + /// # Panics + /// If the dimensions of the inner canvas and mask do not match. + pub fn new(inner: I, mask: M) -> Self { + assert_eq!(inner.dimensions(), mask.dimensions()); + Masked { inner, mask } + } } impl>> Canvas for Masked { From 304cf268f3712f84e2ce09ddc18f8423dbf6bcd5 Mon Sep 17 00:00:00 2001 From: Jibago Date: Wed, 26 Mar 2025 13:52:57 +0900 Subject: [PATCH 4/5] fmt --- examples/masked.rs | 20 ++++++++++++++++---- src/drawing/canvas.rs | 10 +++++----- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/examples/masked.rs b/examples/masked.rs index c118a41c..0332f338 100644 --- a/examples/masked.rs +++ b/examples/masked.rs @@ -1,5 +1,8 @@ use image::{ImageBuffer, Rgb}; -use imageproc::{drawing::{draw_filled_circle, draw_filled_rect_mut}, rect::Rect}; +use imageproc::{ + drawing::{draw_filled_circle, draw_filled_rect_mut}, + rect::Rect, +}; fn main() { // Load the image @@ -10,9 +13,18 @@ fn main() { let shorter_side = mask.width().min(mask.height()) as i32; let center_x = mask.width() / 2; let center_y = mask.height() / 2; - let mask = draw_filled_circle(&mask, (center_x as i32, center_y as i32), shorter_side / 4, image::Luma([255u8])); + let mask = draw_filled_circle( + &mask, + (center_x as i32, center_y as i32), + shorter_side / 4, + image::Luma([255u8]), + ); let mut canvas = imageproc::drawing::Masked::new(image, mask); - draw_filled_rect_mut(&mut canvas, Rect::at(0, 0).of_size(center_x, center_y), Rgb([255u8, 0u8, 0u8])); + draw_filled_rect_mut( + &mut canvas, + Rect::at(0, 0).of_size(center_x, center_y), + Rgb([255u8, 0u8, 0u8]), + ); canvas.inner.save("masked.png").unwrap(); -} \ No newline at end of file +} diff --git a/src/drawing/canvas.rs b/src/drawing/canvas.rs index bb1037fe..d85f0321 100644 --- a/src/drawing/canvas.rs +++ b/src/drawing/canvas.rs @@ -93,7 +93,7 @@ where fn draw_pixel(&mut self, x: u32, y: u32, color: Self::Pixel) { self.put_pixel(x, y, color) } - + fn into_image(self) -> impl GenericImage { self } @@ -121,14 +121,14 @@ impl Canvas for Blend { pix.blend(&color); self.0.draw_pixel(x, y, pix); } - + fn into_image(self) -> impl GenericImage { self.0.into_image() } } /// A canvas that only draws pixels where a mask is non-zero. -pub struct Masked{ +pub struct Masked { /// A canvas to draw on. pub inner: I, /// A mask image where non-zero pixels allow drawing. @@ -137,7 +137,7 @@ pub struct Masked{ impl Masked { /// Create a new masked canvas. - /// + /// /// # Panics /// If the dimensions of the inner canvas and mask do not match. pub fn new(inner: I, mask: M) -> Self { @@ -162,7 +162,7 @@ impl>> Canvas for Masked { self.inner.draw_pixel(x, y, color); } } - + fn into_image(self) -> impl GenericImage { self.inner.into_image() } From 436e63923b92978840f474c390b75147908f1dc0 Mon Sep 17 00:00:00 2001 From: Jibago <54237696+wani3327@users.noreply.github.com> Date: Tue, 1 Apr 2025 21:12:08 +0900 Subject: [PATCH 5/5] it is better to be pub --- src/drawing/canvas.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drawing/canvas.rs b/src/drawing/canvas.rs index d85f0321..59e3f658 100644 --- a/src/drawing/canvas.rs +++ b/src/drawing/canvas.rs @@ -132,7 +132,7 @@ pub struct Masked { /// A canvas to draw on. pub inner: I, /// A mask image where non-zero pixels allow drawing. - mask: M, + pub mask: M, } impl Masked {