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 #[doc(alias = "from_grey_iter")]
128 pub fn from_gray_iter(size: [usize; 2], gray_iter: impl Iterator<Item = u8>) -> Self {
129 let pixels: Vec<_> = gray_iter.map(Color32::from_gray).collect();
130 assert_eq!(size[0] * size[1], pixels.len());
131 Self { size, pixels }
132 }
133
134 #[cfg(feature = "bytemuck")]
136 pub fn as_raw(&self) -> &[u8] {
137 bytemuck::cast_slice(&self.pixels)
138 }
139
140 #[cfg(feature = "bytemuck")]
142 pub fn as_raw_mut(&mut self) -> &mut [u8] {
143 bytemuck::cast_slice_mut(&mut self.pixels)
144 }
145
146 pub fn from_rgb(size: [usize; 2], rgb: &[u8]) -> Self {
153 assert_eq!(size[0] * size[1] * 3, rgb.len());
154 let pixels = rgb
155 .chunks_exact(3)
156 .map(|p| Color32::from_rgb(p[0], p[1], p[2]))
157 .collect();
158 Self { size, pixels }
159 }
160
161 pub fn example() -> Self {
163 let width = 128;
164 let height = 64;
165 let mut img = Self::new([width, height], Color32::TRANSPARENT);
166 for y in 0..height {
167 for x in 0..width {
168 let h = x as f32 / width as f32;
169 let s = 1.0;
170 let v = 1.0;
171 let a = y as f32 / height as f32;
172 img[(x, y)] = crate::Hsva { h, s, v, a }.into();
173 }
174 }
175 img
176 }
177
178 #[inline]
179 pub fn width(&self) -> usize {
180 self.size[0]
181 }
182
183 #[inline]
184 pub fn height(&self) -> usize {
185 self.size[1]
186 }
187
188 pub fn region(&self, region: &emath::Rect, pixels_per_point: Option<f32>) -> Self {
196 let pixels_per_point = pixels_per_point.unwrap_or(1.0);
197 let min_x = (region.min.x * pixels_per_point) as usize;
198 let max_x = (region.max.x * pixels_per_point) as usize;
199 let min_y = (region.min.y * pixels_per_point) as usize;
200 let max_y = (region.max.y * pixels_per_point) as usize;
201 assert!(
202 min_x <= max_x && min_y <= max_y,
203 "Screenshot region is invalid: {region:?}"
204 );
205 let width = max_x - min_x;
206 let height = max_y - min_y;
207 let mut output = Vec::with_capacity(width * height);
208 let row_stride = self.size[0];
209
210 for row in min_y..max_y {
211 output.extend_from_slice(
212 &self.pixels[row * row_stride + min_x..row * row_stride + max_x],
213 );
214 }
215 Self {
216 size: [width, height],
217 pixels: output,
218 }
219 }
220}
221
222impl std::ops::Index<(usize, usize)> for ColorImage {
223 type Output = Color32;
224
225 #[inline]
226 fn index(&self, (x, y): (usize, usize)) -> &Color32 {
227 let [w, h] = self.size;
228 assert!(x < w && y < h);
229 &self.pixels[y * w + x]
230 }
231}
232
233impl std::ops::IndexMut<(usize, usize)> for ColorImage {
234 #[inline]
235 fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Color32 {
236 let [w, h] = self.size;
237 assert!(x < w && y < h);
238 &mut self.pixels[y * w + x]
239 }
240}
241
242impl From<ColorImage> for ImageData {
243 #[inline(always)]
244 fn from(image: ColorImage) -> Self {
245 Self::Color(Arc::new(image))
246 }
247}
248
249impl From<Arc<ColorImage>> for ImageData {
250 #[inline]
251 fn from(image: Arc<ColorImage>) -> Self {
252 Self::Color(image)
253 }
254}
255
256impl std::fmt::Debug for ColorImage {
257 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258 f.debug_struct("ColorImage")
259 .field("size", &self.size)
260 .field("pixel-count", &self.pixels.len())
261 .finish_non_exhaustive()
262 }
263}
264
265#[derive(Clone, Default, PartialEq)]
273#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
274pub struct FontImage {
275 pub size: [usize; 2],
277
278 pub pixels: Vec<f32>,
282}
283
284impl FontImage {
285 pub fn new(size: [usize; 2]) -> Self {
286 Self {
287 size,
288 pixels: vec![0.0; size[0] * size[1]],
289 }
290 }
291
292 #[inline]
293 pub fn width(&self) -> usize {
294 self.size[0]
295 }
296
297 #[inline]
298 pub fn height(&self) -> usize {
299 self.size[1]
300 }
301
302 #[inline]
308 pub fn srgba_pixels(&self, gamma: Option<f32>) -> impl ExactSizeIterator<Item = Color32> + '_ {
309 let gamma = gamma.unwrap_or(0.55);
312 self.pixels.iter().map(move |coverage| {
313 let alpha = coverage.powf(gamma);
314 let a = fast_round(alpha * 255.0);
316 Color32::from_rgba_premultiplied(a, a, a, a)
317 })
318 }
319
320 pub fn region(&self, [x, y]: [usize; 2], [w, h]: [usize; 2]) -> Self {
322 assert!(x + w <= self.width());
323 assert!(y + h <= self.height());
324
325 let mut pixels = Vec::with_capacity(w * h);
326 for y in y..y + h {
327 let offset = y * self.width() + x;
328 pixels.extend(&self.pixels[offset..(offset + w)]);
329 }
330 assert_eq!(pixels.len(), w * h);
331 Self {
332 size: [w, h],
333 pixels,
334 }
335 }
336}
337
338impl std::ops::Index<(usize, usize)> for FontImage {
339 type Output = f32;
340
341 #[inline]
342 fn index(&self, (x, y): (usize, usize)) -> &f32 {
343 let [w, h] = self.size;
344 assert!(x < w && y < h);
345 &self.pixels[y * w + x]
346 }
347}
348
349impl std::ops::IndexMut<(usize, usize)> for FontImage {
350 #[inline]
351 fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut f32 {
352 let [w, h] = self.size;
353 assert!(x < w && y < h);
354 &mut self.pixels[y * w + x]
355 }
356}
357
358impl From<FontImage> for ImageData {
359 #[inline(always)]
360 fn from(image: FontImage) -> Self {
361 Self::Font(image)
362 }
363}
364
365#[inline]
366fn fast_round(r: f32) -> u8 {
367 (r + 0.5) as _ }
369
370#[derive(Clone, PartialEq)]
376#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
377#[must_use = "The painter must take care of this"]
378pub struct ImageDelta {
379 pub image: ImageData,
385
386 pub options: TextureOptions,
387
388 pub pos: Option<[usize; 2]>,
392}
393
394impl ImageDelta {
395 pub fn full(image: impl Into<ImageData>, options: TextureOptions) -> Self {
397 Self {
398 image: image.into(),
399 options,
400 pos: None,
401 }
402 }
403
404 pub fn partial(pos: [usize; 2], image: impl Into<ImageData>, options: TextureOptions) -> Self {
406 Self {
407 image: image.into(),
408 options,
409 pos: Some(pos),
410 }
411 }
412
413 pub fn is_whole(&self) -> bool {
416 self.pos.is_none()
417 }
418}