firefly_rust/graphics/
canvas.rs1use crate::*;
2#[cfg(feature = "alloc")]
3use alloc::boxed::Box;
4#[cfg(feature = "alloc")]
5use alloc::vec;
6
7#[cfg(feature = "alloc")]
15pub struct CanvasBuf {
16 pub(crate) raw: Box<[u8]>,
17}
18
19#[cfg(feature = "alloc")]
20impl CanvasBuf {
21 #[must_use]
23 #[expect(clippy::cast_sign_loss)]
24 pub fn new(s: Size) -> Self {
25 const HEADER_SIZE: usize = 5 + 8;
26 let body_size = s.width * s.height / 2;
27 let mut raw = vec![0; HEADER_SIZE + body_size as usize];
28 prepare_slice(&mut raw, s.width);
29 Self {
30 raw: raw.into_boxed_slice(),
31 }
32 }
33
34 #[must_use]
36 pub const fn as_image(&self) -> Image<'_> {
37 Image { raw: &self.raw }
38 }
39
40 #[must_use]
42 pub const fn as_canvas(&self) -> Canvas<'_> {
43 Canvas { raw: &self.raw }
44 }
45}
46
47pub struct Canvas<'a> {
49 pub(crate) raw: &'a [u8],
50}
51
52impl<'a> Canvas<'a> {
53 #[must_use]
58 #[expect(clippy::cast_sign_loss)]
59 pub fn new(s: Size, raw: &'a mut [u8]) -> Option<Self> {
60 const HEADER_SIZE: usize = 5 + 8;
61 let body_size = s.width * s.height / 2;
62 let exp_size = HEADER_SIZE + body_size as usize;
63 if raw.len() < exp_size {
64 return None;
65 }
66 prepare_slice(raw, s.width);
67 Some(Self {
68 raw: &raw[..exp_size],
69 })
70 }
71
72 #[must_use]
74 pub const fn as_image(&self) -> Image<'a> {
75 Image { raw: self.raw }
76 }
77}
78
79#[cfg(feature = "alloc")]
80impl<'a> From<&'a CanvasBuf> for Canvas<'a> {
81 fn from(value: &'a CanvasBuf) -> Self {
82 Self { raw: &value.raw }
83 }
84}
85
86#[expect(clippy::cast_sign_loss)]
87fn prepare_slice(raw: &mut [u8], width: i32) {
88 raw[0] = 0x21; raw[1] = 4; raw[2] = width as u8; raw[3] = (width >> 8) as u8; raw[4] = 255; for i in 0u8..8u8 {
96 raw[5 + i as usize] = ((i * 2) << 4) | (i * 2 + 1);
97 }
98}