imageproc/drawing/
canvas.rs

1use image::{GenericImage, GenericImageView, Pixel};
2
3/// A surface for drawing on - many drawing functions in this
4/// library are generic over a `Canvas` to allow the user to
5/// configure e.g. whether to use blending.
6///
7/// All instances of `GenericImage` implement `Canvas`, with
8/// the behaviour of `draw_pixel` being equivalent to calling
9/// `set_pixel` with the same arguments.
10///
11/// See [`Blend`](struct.Blend.html) for another example implementation
12/// of this trait - its implementation of `draw_pixel` alpha-blends
13/// the input value with the pixel's current value.
14///
15/// # Examples
16/// ```
17/// # extern crate image;
18/// # #[macro_use]
19/// # extern crate imageproc;
20/// # fn main() {
21/// use image::{Pixel, Rgba, RgbaImage};
22/// use imageproc::drawing::{Canvas, Blend};
23///
24/// // A trivial function which draws on a Canvas
25/// fn write_a_pixel<C: Canvas>(canvas: &mut C, c: C::Pixel) {
26///     canvas.draw_pixel(0, 0, c);
27/// }
28///
29/// // Background color
30/// let solid_blue = Rgba([0u8, 0u8, 255u8, 255u8]);
31///
32/// // Drawing color
33/// let translucent_red = Rgba([255u8, 0u8, 0u8, 127u8]);
34///
35/// // Blended combination of background and drawing colors
36/// let mut alpha_blended = solid_blue;
37/// alpha_blended.blend(&translucent_red);
38///
39/// // The implementation of Canvas for GenericImage overwrites existing pixels
40/// let mut image = RgbaImage::from_pixel(1, 1, solid_blue);
41/// write_a_pixel(&mut image, translucent_red);
42/// assert_eq!(*image.get_pixel(0, 0), translucent_red);
43///
44/// // This behaviour can be customised by using a different Canvas type
45/// let mut image = Blend(RgbaImage::from_pixel(1, 1, solid_blue));
46/// write_a_pixel(&mut image, translucent_red);
47/// assert_eq!(*image.0.get_pixel(0, 0), alpha_blended);
48/// # }
49/// ```
50pub trait Canvas {
51    /// The type of `Pixel` that can be drawn on this canvas.
52    type Pixel: Pixel;
53
54    /// The width and height of this canvas.
55    fn dimensions(&self) -> (u32, u32);
56
57    /// The width of this canvas.
58    fn width(&self) -> u32 {
59        self.dimensions().0
60    }
61
62    /// The height of this canvas.
63    fn height(&self) -> u32 {
64        self.dimensions().1
65    }
66
67    /// Returns the pixel located at (x, y).
68    fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel;
69
70    /// Draw a pixel at the given coordinates. `x` and `y`
71    /// should be within `dimensions` - if not then panicking
72    /// is a valid implementation behaviour.
73    fn draw_pixel(&mut self, x: u32, y: u32, color: Self::Pixel);
74}
75
76impl<I> Canvas for I
77where
78    I: GenericImage,
79{
80    type Pixel = I::Pixel;
81
82    fn dimensions(&self) -> (u32, u32) {
83        <I as GenericImageView>::dimensions(self)
84    }
85
86    fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
87        self.get_pixel(x, y)
88    }
89
90    fn draw_pixel(&mut self, x: u32, y: u32, color: Self::Pixel) {
91        self.put_pixel(x, y, color)
92    }
93}
94
95/// A canvas that blends pixels when drawing.
96///
97/// See the documentation for [`Canvas`](trait.Canvas.html)
98/// for an example using this type.
99pub struct Blend<I>(pub I);
100
101impl<I: GenericImage> Canvas for Blend<I> {
102    type Pixel = I::Pixel;
103
104    fn dimensions(&self) -> (u32, u32) {
105        self.0.dimensions()
106    }
107
108    fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel {
109        self.0.get_pixel(x, y)
110    }
111
112    fn draw_pixel(&mut self, x: u32, y: u32, color: Self::Pixel) {
113        let mut pix = self.0.get_pixel(x, y);
114        pix.blend(&color);
115        self.0.put_pixel(x, y, pix);
116    }
117}