1use crate::Size;
3
4use std::mem;
5
6pub fn from_rgba(rgba: Vec<u8>, width: u32, height: u32) -> Result<Icon, Error> {
8 const PIXEL_SIZE: usize = mem::size_of::<u8>() * 4;
9
10 if !rgba.len().is_multiple_of(PIXEL_SIZE) {
11 return Err(Error::ByteCountNotDivisibleBy4 {
12 byte_count: rgba.len(),
13 });
14 }
15
16 let pixel_count = rgba.len() / PIXEL_SIZE;
17
18 if pixel_count != (width * height) as usize {
19 return Err(Error::DimensionsVsPixelCount {
20 width,
21 height,
22 width_x_height: (width * height) as usize,
23 pixel_count,
24 });
25 }
26
27 Ok(Icon {
28 rgba,
29 size: Size::new(width, height),
30 })
31}
32
33#[derive(Clone)]
35pub struct Icon {
36 rgba: Vec<u8>,
37 size: Size<u32>,
38}
39
40impl Icon {
41 pub fn into_raw(self) -> (Vec<u8>, Size<u32>) {
43 (self.rgba, self.size)
44 }
45}
46
47impl std::fmt::Debug for Icon {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 f.debug_struct("Icon")
50 .field("rgba", &format!("{} pixels", self.rgba.len() / 4))
51 .field("size", &self.size)
52 .finish()
53 }
54}
55
56#[derive(Debug, thiserror::Error)]
57pub enum Error {
59 #[error(
62 "The provided RGBA data (with length {byte_count}) isn't divisible \
63 by 4. Therefore, it cannot be safely interpreted as 32bpp RGBA pixels"
64 )]
65 ByteCountNotDivisibleBy4 {
66 byte_count: usize,
68 },
69 #[error(
72 "The number of RGBA pixels ({pixel_count}) does not match the \
73 provided dimensions ({width}x{height})."
74 )]
75 DimensionsVsPixelCount {
76 width: u32,
78 height: u32,
80 width_x_height: usize,
82 pixel_count: usize,
84 },
85}