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}