Skip to main content

yog_graphics/
image.rs

1//! RGBA images.
2
3use yog_data::Schema;
4use yog_data::with::Raw;
5
6use crate::color::Color;
7
8/// Bytes per pixel: red, green, blue, alpha.
9pub const BYTES_PER_PIXEL: usize = 4;
10
11/// One RGBA8 pixel.
12pub type Rgba8 = [u8; BYTES_PER_PIXEL];
13
14/// Pixels, RGBA8 row by row from the top, straight alpha.
15#[derive(Schema, Debug, Clone, PartialEq, Default)]
16pub struct Image {
17    pub width: u32,
18    pub height: u32,
19    /// Written as bytes, not a list of numbers.
20    #[data(with = "Raw")]
21    pub rgba: Vec<u8>,
22}
23
24impl Image {
25    /// A transparent `width × height` image.
26    pub fn new(width: u32, height: u32) -> Image {
27        Image {
28            width,
29            height,
30            rgba: vec![0; width as usize * height as usize * BYTES_PER_PIXEL],
31        }
32    }
33
34    /// The pixels, row by row from the top.
35    pub fn pixels(&self) -> &[Rgba8] {
36        self.rgba.as_chunks().0
37    }
38
39    /// The pixels to change, row by row from the top.
40    pub fn pixels_mut(&mut self) -> &mut [Rgba8] {
41        self.rgba.as_chunks_mut().0
42    }
43
44    pub fn is_empty(&self) -> bool {
45        self.width == 0 || self.height == 0
46    }
47
48    /// Pixel `x, y`'s place in [`Self::pixels`].
49    fn index(&self, x: u32, y: u32) -> usize {
50        (y * self.width + x) as usize
51    }
52
53    pub fn pixel(&self, x: u32, y: u32) -> Color {
54        Color::from_rgba8(self.pixels()[self.index(x, y)])
55    }
56
57    pub fn set_pixel(&mut self, x: u32, y: u32, c: Color) {
58        let i = self.index(x, y);
59        self.pixels_mut()[i] = c.to_rgba8();
60    }
61}
62
63/// An image and where it goes: its top-left corner `x, y` pixels (`y`
64/// down) from the origin it was drawn for — a glyph's from its pen
65/// position on the baseline, say.
66#[derive(Debug, Clone, PartialEq, Default)]
67pub struct PlacedImage {
68    pub image: Image,
69    pub x: i32,
70    pub y: i32,
71}