1#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5pub enum PixelFormat {
6 Rgba8,
8
9 Bgra8,
11}
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
15pub enum AlphaType {
16 Premultiplied,
18
19 Straight,
21}
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub struct PixelLayout {
26 pub size: [u32; 2],
28
29 pub row_bytes: u32,
31
32 pub format: PixelFormat,
34
35 pub alpha: AlphaType,
37}
38
39impl PixelLayout {
40 pub fn packed(size: [u32; 2], format: PixelFormat, alpha: AlphaType) -> Self {
42 Self {
43 size,
44 row_bytes: size[0].saturating_mul(4),
45 format,
46 alpha,
47 }
48 }
49
50 pub fn byte_len(self) -> Result<usize, ImageError> {
52 let width = self.size[0]
53 .checked_mul(4)
54 .ok_or(ImageError::InvalidLayout)?;
55 if self.size.contains(&0) || self.row_bytes < width {
56 return Err(ImageError::InvalidLayout);
57 }
58 usize::try_from(u64::from(self.row_bytes) * u64::from(self.size[1]))
59 .map_err(|_| ImageError::InvalidLayout)
60 }
61}
62
63pub struct PixelBuffer {
68 layout: PixelLayout,
69 pixels: Vec<u8>,
70}
71
72impl PixelBuffer {
73 pub fn new(layout: PixelLayout, pixels: Vec<u8>) -> Result<Self, ImageError> {
75 if pixels.len() != layout.byte_len()? {
76 return Err(ImageError::InvalidLayout);
77 }
78 Ok(Self { layout, pixels })
79 }
80
81 pub fn layout(&self) -> PixelLayout {
83 self.layout
84 }
85
86 pub(crate) fn into_premultiplied_rgba(self) -> Vec<u8> {
88 let Self { layout, mut pixels } = self;
89 let row = layout.size[0] as usize * 4;
90 for y in 0..layout.size[1] as usize {
91 let from = y * layout.row_bytes as usize;
92 pixels.copy_within(from..from + row, y * row);
93 normalize_row(&mut pixels[y * row..(y + 1) * row], layout);
94 }
95 pixels.truncate(row * layout.size[1] as usize);
96 pixels
97 }
98}
99
100fn normalize_row(row: &mut [u8], layout: PixelLayout) {
101 for pixel in row.chunks_exact_mut(4) {
102 if layout.format == PixelFormat::Bgra8 {
103 pixel.swap(0, 2);
104 }
105 if layout.alpha == AlphaType::Straight {
106 premultiply(pixel);
107 }
108 }
109}
110
111fn premultiply(pixel: &mut [u8]) {
112 let alpha = u16::from(pixel[3]);
113 for channel in &mut pixel[..3] {
114 *channel = ((u16::from(*channel) * alpha + 127) / 255) as u8;
115 }
116}
117
118#[derive(Clone, Debug, PartialEq, Eq)]
120pub enum ImageError {
121 InvalidLayout,
123
124 TooLarge,
126
127 IncompatibleTexture,
129
130 WrongDevice,
132
133 UnsupportedBackend,
135}
136
137impl std::fmt::Display for ImageError {
138 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139 write!(f, "{self:?}")
140 }
141}
142
143impl std::error::Error for ImageError {}