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