Skip to content

Add a new mask canvas #715

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions examples/masked.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use image::{ImageBuffer, Rgb};
use imageproc::{
drawing::{draw_filled_circle, draw_filled_rect_mut},
rect::Rect,
};

fn main() {
// Load the image
let image = ImageBuffer::<Rgb<u8>, 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::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();
}
58 changes: 55 additions & 3 deletions src/drawing/canvas.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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<I> Canvas for I
Expand All @@ -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.
Expand All @@ -98,7 +105,7 @@ where
/// for an example using this type.
pub struct Blend<I>(pub I);

impl<I: GenericImage> Canvas for Blend<I> {
impl<I: Canvas> Canvas for Blend<I> {
type Pixel = I::Pixel;

fn dimensions(&self) -> (u32, u32) {
Expand All @@ -112,6 +119,51 @@ impl<I: GenericImage> Canvas for Blend<I> {
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);
}

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<I, M> {
/// A canvas to draw on.
pub inner: I,
/// A mask image where non-zero pixels allow drawing.
pub mask: M,
}

impl<I: Canvas, M: Canvas> Masked<I, M> {
/// 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<I: Canvas, M: GenericImage<Pixel = Luma<u8>>> Canvas for Masked<I, M> {
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);
}
}

fn into_image(self) -> impl GenericImage {
self.inner.into_image()
}
}
2 changes: 1 addition & 1 deletion src/drawing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down
Loading