pixel_canvas/
image.rs

1//! The [`Image`] is what you manipulate to produce your art.
2//!
3//! Every frame you are given a mutable reference to the existing frame, and
4//! are able to modify it to produce your image.
5//!
6//! [`Image`]: struct.Image.html
7
8// @Todo: Add multiple pixel formats?
9// @Todo: Seaparate stride from width, and document.
10
11use crate::color::Color;
12use glium::texture::{ClientFormat, RawImage2d, Texture2dDataSource};
13use std::{
14    borrow::Cow,
15    ops::{Deref, DerefMut, Index, IndexMut},
16};
17
18/// An image for editing.
19///
20/// It dereferences to a slice of [`Color`], so you can directly manipulate
21/// pixels via regular (mutable) slice methods. In addition, you can index
22/// into the image by `(row, column)` pairs.
23///
24/// [`Color`]: ../color/struct.Color.html
25pub struct Image {
26    width: usize,
27    height: usize,
28    pixels: Vec<Color>,
29}
30
31/// A row/column pair for indexing into an image.
32/// Distinct from an x/y pair.
33pub struct RC(pub usize, pub usize);
34
35/// An x/y pair for indexing into an image.
36/// Distinct from a row/column pair.
37pub struct XY(pub usize, pub usize);
38
39impl Image {
40    /// The width of the image in pixels.
41    pub fn width(&self) -> usize {
42        self.width
43    }
44
45    /// The height of the image in pixels.
46    pub fn height(&self) -> usize {
47        self.height
48    }
49
50    /// Create an all-black image with the given dimensions.
51    pub fn new(width: usize, height: usize) -> Image {
52        Image {
53            width,
54            height,
55            pixels: vec![Color { r: 0, g: 0, b: 0 }; (width * height) as usize],
56        }
57    }
58
59    /// Fill the image with a single solid color.
60    pub fn fill(&mut self, color: Color) {
61        for pix in &mut self.pixels {
62            *pix = color;
63        }
64    }
65}
66
67impl Index<RC> for Image {
68    type Output = Color;
69    fn index(&self, RC(row, col): RC) -> &Self::Output {
70        &self.pixels[(row * self.width + col) as usize]
71    }
72}
73
74impl IndexMut<RC> for Image {
75    fn index_mut(&mut self, RC(row, col): RC) -> &mut Self::Output {
76        &mut self.pixels[(row * self.width + col) as usize]
77    }
78}
79
80impl Index<XY> for Image {
81    type Output = Color;
82    fn index(&self, XY(x, y): XY) -> &Self::Output {
83        &self.pixels[(y * self.width + x) as usize]
84    }
85}
86
87impl IndexMut<XY> for Image {
88    fn index_mut(&mut self, XY(x, y): XY) -> &mut Self::Output {
89        &mut self.pixels[(y * self.width + x) as usize]
90    }
91}
92
93impl Deref for Image {
94    type Target = [Color];
95    fn deref(&self) -> &Self::Target {
96        &self.pixels
97    }
98}
99
100impl DerefMut for Image {
101    fn deref_mut(&mut self) -> &mut Self::Target {
102        &mut self.pixels
103    }
104}
105
106impl<'a> Texture2dDataSource<'a> for &'a Image {
107    type Data = u8;
108    fn into_raw(self) -> RawImage2d<'a, Self::Data> {
109        RawImage2d {
110            data: Cow::Borrowed(unsafe {
111                std::slice::from_raw_parts(self.pixels.as_ptr() as *const u8, self.pixels.len() * 3)
112            }),
113            width: self.width as u32,
114            height: self.height as u32,
115            format: ClientFormat::U8U8U8,
116        }
117    }
118}