1use wide::u32x4;
2use xxhash_rust::xxh3::xxh3_64_with_seed;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
5pub enum ImageFilter {
6 #[default]
7 Nearest,
8 Linear,
9}
10
11pub trait ExternalTexture: std::fmt::Debug + Send + Sync {
21 fn as_any(&self) -> &dyn std::any::Any;
22}
23
24#[derive(Debug, Clone)]
25enum ImageSource {
26 Pixels(Vec<u8>),
27 External(std::sync::Arc<dyn ExternalTexture>),
28}
29
30#[derive(Debug, Clone)]
31pub struct ImageData {
32 pub id: u64,
39 source: ImageSource,
40 pub width: u32,
41 pub height: u32,
42}
43
44impl ImageData {
45 pub fn new(pixels: Vec<u8>, width: u32, height: u32) -> Self {
46 assert_eq!(
47 pixels.len(),
48 (width * height * 4) as usize,
49 "pixels must be RGBA8: width * height * 4 bytes"
50 );
51 let mut pixels = pixels;
52 premultiply_rgba(&mut pixels);
53 Self::addressed(pixels, width, height)
54 }
55
56 pub fn from_premultiplied(pixels: Vec<u8>, width: u32, height: u32) -> Self {
58 assert_eq!(
59 pixels.len(),
60 (width * height * 4) as usize,
61 "pixels must be RGBA8: width * height * 4 bytes"
62 );
63 Self::addressed(pixels, width, height)
64 }
65
66 pub fn external(
72 texture: std::sync::Arc<dyn ExternalTexture>,
73 id: u64,
74 width: u32,
75 height: u32,
76 ) -> Self {
77 Self {
78 id,
79 source: ImageSource::External(texture),
80 width,
81 height,
82 }
83 }
84
85 pub fn pixels(&self) -> &[u8] {
91 match &self.source {
92 ImageSource::Pixels(p) => p,
93 ImageSource::External(_) => &[],
94 }
95 }
96
97 pub fn external_texture(&self) -> Option<&std::sync::Arc<dyn ExternalTexture>> {
98 match &self.source {
99 ImageSource::External(t) => Some(t),
100 ImageSource::Pixels(_) => None,
101 }
102 }
103
104 fn addressed(pixels: Vec<u8>, width: u32, height: u32) -> Self {
106 let seed = ((width as u64) << 32) | height as u64;
107 Self {
108 id: xxh3_64_with_seed(&pixels, seed),
109 source: ImageSource::Pixels(pixels),
110 width,
111 height,
112 }
113 }
114}
115
116#[inline]
117pub fn premultiply_rgba(pixels: &mut [u8]) {
118 let mut iter = pixels.chunks_exact_mut(16);
119 for chunk in iter.by_ref() {
120 let r = u32x4::new([
121 chunk[0] as u32,
122 chunk[4] as u32,
123 chunk[8] as u32,
124 chunk[12] as u32,
125 ]);
126 let g = u32x4::new([
127 chunk[1] as u32,
128 chunk[5] as u32,
129 chunk[9] as u32,
130 chunk[13] as u32,
131 ]);
132 let b = u32x4::new([
133 chunk[2] as u32,
134 chunk[6] as u32,
135 chunk[10] as u32,
136 chunk[14] as u32,
137 ]);
138 let a = u32x4::new([
139 chunk[3] as u32,
140 chunk[7] as u32,
141 chunk[11] as u32,
142 chunk[15] as u32,
143 ]);
144 let bias = u32x4::splat(128);
145 let shift = u32x4::splat(8);
146 let r_new = ((r * a) + bias) >> shift;
147 let g_new = ((g * a) + bias) >> shift;
148 let b_new = ((b * a) + bias) >> shift;
149 let ra = r_new.to_array();
150 let ga = g_new.to_array();
151 let ba = b_new.to_array();
152 chunk[0] = ra[0] as u8;
153 chunk[4] = ra[1] as u8;
154 chunk[8] = ra[2] as u8;
155 chunk[12] = ra[3] as u8;
156 chunk[1] = ga[0] as u8;
157 chunk[5] = ga[1] as u8;
158 chunk[9] = ga[2] as u8;
159 chunk[13] = ga[3] as u8;
160 chunk[2] = ba[0] as u8;
161 chunk[6] = ba[1] as u8;
162 chunk[10] = ba[2] as u8;
163 chunk[14] = ba[3] as u8;
164 }
165 for chunk in iter.into_remainder().chunks_exact_mut(4) {
166 let a = chunk[3] as u32;
167 chunk[0] = ((chunk[0] as u32 * a + 128) >> 8) as u8;
168 chunk[1] = ((chunk[1] as u32 * a + 128) >> 8) as u8;
169 chunk[2] = ((chunk[2] as u32 * a + 128) >> 8) as u8;
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 fn opaque(pixels: &[[u8; 3]]) -> Vec<u8> {
178 pixels
179 .iter()
180 .flat_map(|[r, g, b]| [*r, *g, *b, 255])
181 .collect()
182 }
183
184 #[test]
186 fn the_same_image_built_twice_gets_the_same_id() {
187 let once = ImageData::new(opaque(&[[10, 20, 30], [40, 50, 60]]), 2, 1);
188 let again = ImageData::new(opaque(&[[10, 20, 30], [40, 50, 60]]), 2, 1);
189 assert_eq!(once.id, again.id);
190 }
191
192 #[test]
193 fn different_pixels_get_different_ids() {
194 let a = ImageData::new(opaque(&[[10, 20, 30], [40, 50, 60]]), 2, 1);
195 let b = ImageData::new(opaque(&[[10, 20, 30], [40, 50, 61]]), 2, 1);
196 assert_ne!(a.id, b.id);
197 }
198
199 #[test]
201 fn the_same_bytes_at_different_dimensions_get_different_ids() {
202 let wide = ImageData::new(
203 opaque(&[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]),
204 4,
205 1,
206 );
207 let square = ImageData::new(
208 opaque(&[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]),
209 2,
210 2,
211 );
212 assert_ne!(wide.id, square.id);
213 }
214
215 #[test]
217 fn both_constructors_address_the_same_finished_image_alike() {
218 let half_alpha = vec![200, 100, 50, 128];
219 let mut premultiplied = half_alpha.clone();
220 premultiply_rgba(&mut premultiplied);
221 assert_eq!(
222 ImageData::new(half_alpha, 1, 1).id,
223 ImageData::from_premultiplied(premultiplied, 1, 1).id
224 );
225 }
226}