1use crate::{textures::TextureOptions, Color32};
2use std::sync::Arc;
3
4#[derive(Clone, PartialEq)]
12#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
13pub enum ImageData {
14 Color(Arc<ColorImage>),
16
17 Font(FontImage),
19}
20
21impl ImageData {
22 pub fn size(&self) -> [usize; 2] {
23 match self {
24 Self::Color(image) => image.size,
25 Self::Font(image) => image.size,
26 }
27 }
28
29 pub fn width(&self) -> usize {
30 self.size()[0]
31 }
32
33 pub fn height(&self) -> usize {
34 self.size()[1]
35 }
36
37 pub fn bytes_per_pixel(&self) -> usize {
38 match self {
39 Self::Color(_) | Self::Font(_) => 4,
40 }
41 }
42}
43
44#[derive(Clone, Default, PartialEq, Eq)]
48#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
49pub struct ColorImage {
50 pub size: [usize; 2],
52
53 pub pixels: Vec<Color32>,
55}
56
57impl ColorImage {
58 pub fn new(size: [usize; 2], color: Color32) -> Self {
60 Self {
61 size,
62 pixels: vec![color; size[0] * size[1]],
63 }
64 }
65
66 pub fn from_rgba_unmultiplied(size: [usize; 2], rgba: &[u8]) -> Self {
97 assert_eq!(size[0] * size[1] * 4, rgba.len());
98 let pixels = rgba
99 .chunks_exact(4)
100 .map(|p| Color32::from_rgba_unmultiplied(p[0], p[1], p[2], p[3]))
101 .collect();
102 Self { size, pixels }
103 }
104
105 pub fn from_rgba_premultiplied(size: [usize; 2], rgba: &[u8]) -> Self {
106 assert_eq!(size[0] * size[1] * 4, rgba.len());
107 let pixels = rgba
108 .chunks_exact(4)
109 .map(|p| Color32::from_rgba_premultiplied(p[0], p[1], p[2], p[3]))
110 .collect();
111 Self { size, pixels }
112 }
113
114 pub fn from_gray(size: [usize; 2], gray: &[u8]) -> Self {
118 assert_eq!(size[0] * size[1], gray.len());
119 let pixels = gray.iter().map(|p| Color32::from_gray(*p)).collect();
120 Self { size, pixels }
121 }
122
123 pub fn from_gray_iter(size: [usize; 2], gray_iter: impl Iterator<Item = u8>) -> Self {
128 let pixels: Vec<_> = gray_iter.map(Color32::from_gray).collect();
129 assert_eq!(size[0] * size[1], pixels.len());
130 Self { size, pixels }
131 }
132
133 #[cfg(feature = "bytemuck")]
135 pub fn as_raw(&self) -> &[u8] {
136 bytemuck::cast_slice(&self.pixels)
137 }
138
139 #[cfg(feature = "bytemuck")]
141 pub fn as_raw_mut(&mut self) -> &mut [u8] {
142 bytemuck::cast_slice_mut(&mut self.pixels)
143 }
144
145 pub fn region(&self, region: &emath::Rect, pixels_per_point: Option<f32>) -> Self {
151 let pixels_per_point = pixels_per_point.unwrap_or(1.0);
152 let min_x = (region.min.x * pixels_per_point) as usize;
153 let max_x = (region.max.x * pixels_per_point) as usize;
154 let min_y = (region.min.y * pixels_per_point) as usize;
155 let max_y = (region.max.y * pixels_per_point) as usize;
156 assert!(min_x <= max_x);
157 assert!(min_y <= max_y);
158 let width = max_x - min_x;
159 let height = max_y - min_y;
160 let mut output = Vec::with_capacity(width * height);
161 let row_stride = self.size[0];
162
163 for row in min_y..max_y {
164 output.extend_from_slice(
165 &self.pixels[row * row_stride + min_x..row * row_stride + max_x],
166 );
167 }
168 Self {
169 size: [width, height],
170 pixels: output,
171 }
172 }
173
174 pub fn from_rgb(size: [usize; 2], rgb: &[u8]) -> Self {
181 assert_eq!(size[0] * size[1] * 3, rgb.len());
182 let pixels = rgb
183 .chunks_exact(3)
184 .map(|p| Color32::from_rgb(p[0], p[1], p[2]))
185 .collect();
186 Self { size, pixels }
187 }
188
189 pub fn example() -> Self {
191 let width = 128;
192 let height = 64;
193 let mut img = Self::new([width, height], Color32::TRANSPARENT);
194 for y in 0..height {
195 for x in 0..width {
196 let h = x as f32 / width as f32;
197 let s = 1.0;
198 let v = 1.0;
199 let a = y as f32 / height as f32;
200 img[(x, y)] = crate::Hsva { h, s, v, a }.into();
201 }
202 }
203 img
204 }
205
206 #[inline]
207 pub fn width(&self) -> usize {
208 self.size[0]
209 }
210
211 #[inline]
212 pub fn height(&self) -> usize {
213 self.size[1]
214 }
215}
216
217impl std::ops::Index<(usize, usize)> for ColorImage {
218 type Output = Color32;
219
220 #[inline]
221 fn index(&self, (x, y): (usize, usize)) -> &Color32 {
222 let [w, h] = self.size;
223 assert!(x < w && y < h);
224 &self.pixels[y * w + x]
225 }
226}
227
228impl std::ops::IndexMut<(usize, usize)> for ColorImage {
229 #[inline]
230 fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Color32 {
231 let [w, h] = self.size;
232 assert!(x < w && y < h);
233 &mut self.pixels[y * w + x]
234 }
235}
236
237impl From<ColorImage> for ImageData {
238 #[inline(always)]
239 fn from(image: ColorImage) -> Self {
240 Self::Color(Arc::new(image))
241 }
242}
243
244impl From<Arc<ColorImage>> for ImageData {
245 #[inline]
246 fn from(image: Arc<ColorImage>) -> Self {
247 Self::Color(image)
248 }
249}
250
251impl std::fmt::Debug for ColorImage {
252 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
253 f.debug_struct("ColorImage")
254 .field("size", &self.size)
255 .field("pixel-count", &self.pixels.len())
256 .finish_non_exhaustive()
257 }
258}
259
260#[derive(Clone, Default, PartialEq)]
268#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
269pub struct FontImage {
270 pub size: [usize; 2],
272
273 pub pixels: Vec<f32>,
277}
278
279impl FontImage {
280 pub fn new(size: [usize; 2]) -> Self {
281 Self {
282 size,
283 pixels: vec![0.0; size[0] * size[1]],
284 }
285 }
286
287 #[inline]
288 pub fn width(&self) -> usize {
289 self.size[0]
290 }
291
292 #[inline]
293 pub fn height(&self) -> usize {
294 self.size[1]
295 }
296
297 #[inline]
303 pub fn srgba_pixels(&self, gamma: Option<f32>) -> impl ExactSizeIterator<Item = Color32> + '_ {
304 let gamma = gamma.unwrap_or(0.55); self.pixels.iter().map(move |coverage| {
306 let alpha = coverage.powf(gamma);
307 let a = fast_round(alpha * 255.0);
309 Color32::from_rgba_premultiplied(a, a, a, a)
310 })
311 }
312
313 pub fn region(&self, [x, y]: [usize; 2], [w, h]: [usize; 2]) -> Self {
315 assert!(x + w <= self.width());
316 assert!(y + h <= self.height());
317
318 let mut pixels = Vec::with_capacity(w * h);
319 for y in y..y + h {
320 let offset = y * self.width() + x;
321 pixels.extend(&self.pixels[offset..(offset + w)]);
322 }
323 assert_eq!(pixels.len(), w * h);
324 Self {
325 size: [w, h],
326 pixels,
327 }
328 }
329}
330
331impl std::ops::Index<(usize, usize)> for FontImage {
332 type Output = f32;
333
334 #[inline]
335 fn index(&self, (x, y): (usize, usize)) -> &f32 {
336 let [w, h] = self.size;
337 assert!(x < w && y < h);
338 &self.pixels[y * w + x]
339 }
340}
341
342impl std::ops::IndexMut<(usize, usize)> for FontImage {
343 #[inline]
344 fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut f32 {
345 let [w, h] = self.size;
346 assert!(x < w && y < h);
347 &mut self.pixels[y * w + x]
348 }
349}
350
351impl From<FontImage> for ImageData {
352 #[inline(always)]
353 fn from(image: FontImage) -> Self {
354 Self::Font(image)
355 }
356}
357
358#[inline]
359fn fast_round(r: f32) -> u8 {
360 (r + 0.5) as _ }
362
363#[derive(Clone, PartialEq)]
369#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
370#[must_use = "The painter must take care of this"]
371pub struct ImageDelta {
372 pub image: ImageData,
378
379 pub options: TextureOptions,
380
381 pub pos: Option<[usize; 2]>,
385}
386
387impl ImageDelta {
388 pub fn full(image: impl Into<ImageData>, options: TextureOptions) -> Self {
390 Self {
391 image: image.into(),
392 options,
393 pos: None,
394 }
395 }
396
397 pub fn partial(pos: [usize; 2], image: impl Into<ImageData>, options: TextureOptions) -> Self {
399 Self {
400 image: image.into(),
401 options,
402 pos: Some(pos),
403 }
404 }
405
406 pub fn is_whole(&self) -> bool {
409 self.pos.is_none()
410 }
411}