firefly_rust/graphics/
image.rs

1use crate::*;
2
3/// A loaded image file.
4///
5/// Can be loaded as [`FileBuf`] from ROM with [`load_file_buf`]
6/// and then cast using [`Into`].
7pub struct Image<'a> {
8    pub(crate) raw: &'a [u8],
9}
10
11impl<'a> From<File<'a>> for Image<'a> {
12    fn from(value: File<'a>) -> Self {
13        Self { raw: value.raw }
14    }
15}
16
17#[cfg(feature = "alloc")]
18impl<'a> From<&'a FileBuf> for Image<'a> {
19    fn from(value: &'a FileBuf) -> Self {
20        Self { raw: &value.raw }
21    }
22}
23
24impl<'a> From<Canvas<'a>> for Image<'a> {
25    fn from(value: Canvas<'a>) -> Self {
26        Self { raw: value.raw }
27    }
28}
29
30#[cfg(feature = "alloc")]
31impl<'a> From<&'a CanvasBuf> for Image<'a> {
32    fn from(value: &'a CanvasBuf) -> Self {
33        Self { raw: &value.raw }
34    }
35}
36
37impl<'a> Image<'a> {
38    /// Get a rectangle subregion of the image.
39    #[must_use]
40    pub const fn sub(&self, p: Point, s: Size) -> SubImage<'a> {
41        SubImage {
42            point: p,
43            size: s,
44            raw: self.raw,
45        }
46    }
47
48    /// Bits per pixel. One of: 1, 2, or 4.
49    #[must_use]
50    pub const fn bpp(&self) -> u8 {
51        self.raw[1]
52    }
53
54    /// The color used for transparency. If no transparency, returns [`Color::None`].
55    #[must_use]
56    pub fn transparency(&self) -> Color {
57        let c = usize::from(self.raw[4]) + 1;
58        c.try_into().unwrap_or(Color::None)
59    }
60
61    // pub fn set_transparency(&mut self, c: Color) {
62    //     let c: i32 = c.into();
63    //     if c == 0 {
64    //         self.raw[4] = 16;
65    //     } else {
66    //         self.raw[4] = c as u8;
67    //     }
68    // }
69
70    /// The number of pixels the image has.
71    #[must_use]
72    pub const fn pixels(&self) -> usize {
73        self.raw.len() * 8 / self.bpp() as usize
74    }
75
76    /// The image width in pixels.
77    #[must_use]
78    pub fn width(&self) -> u16 {
79        let big = u16::from(self.raw[2]);
80        let little = u16::from(self.raw[3]);
81        big | (little << 8)
82    }
83
84    /// The image height in pixels.
85    #[must_use]
86    pub fn height(&self) -> u16 {
87        let p = self.pixels();
88        let w = self.width() as usize;
89        p.checked_div(w).unwrap_or(0) as u16
90    }
91
92    /// The image size in pixels.
93    #[must_use]
94    pub fn size(&self) -> Size {
95        Size {
96            width: i32::from(self.width()),
97            height: i32::from(self.height()),
98        }
99    }
100
101    /// Get the color used to represent the given pixel value.
102    #[must_use]
103    pub fn get_color(&self, p: u8) -> Color {
104        if p > 15 {
105            return Color::None;
106        }
107        let byte_idx = usize::from(5 + p / 2);
108        let mut byte_val = self.raw[byte_idx];
109        if p % 2 == 0 {
110            byte_val >>= 4;
111        }
112        byte_val &= 0b1111;
113        let transp = self.raw[4];
114        if byte_val == transp {
115            return Color::None;
116        }
117        let color_val = usize::from(byte_val + 1);
118        color_val.try_into().unwrap_or(Color::None)
119    }
120}
121
122/// A subregion of an image. Constructed using [`Image::sub`].
123pub struct SubImage<'a> {
124    pub(crate) point: Point,
125    pub(crate) size: Size,
126    pub(crate) raw: &'a [u8],
127}