1use emath::Vec2;
2
3use crate::{Color32, textures::TextureOptions};
4use std::sync::Arc;
5
6#[derive(Clone, PartialEq, Eq)]
14#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
15pub enum ImageData {
16 Color(Arc<ColorImage>),
18}
19
20impl ImageData {
21 pub fn size(&self) -> [usize; 2] {
22 match self {
23 Self::Color(image) => image.size,
24 }
25 }
26
27 pub fn width(&self) -> usize {
28 self.size()[0]
29 }
30
31 pub fn height(&self) -> usize {
32 self.size()[1]
33 }
34
35 pub fn bytes_per_pixel(&self) -> usize {
36 match self {
37 Self::Color(_) => 4,
38 }
39 }
40}
41
42#[derive(Clone, Default, PartialEq, Eq)]
46#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
47pub struct ColorImage {
48 pub size: [usize; 2],
50
51 pub source_size: Vec2,
53
54 pub pixels: Vec<Color32>,
56}
57
58impl ColorImage {
59 pub fn new(size: [usize; 2], pixels: Vec<Color32>) -> Self {
61 debug_assert!(
62 size[0] * size[1] == pixels.len(),
63 "size: {size:?}, pixels.len(): {}",
64 pixels.len()
65 );
66 Self {
67 size,
68 source_size: Vec2::new(size[0] as f32, size[1] as f32),
69 pixels,
70 }
71 }
72
73 pub fn filled(size: [usize; 2], color: Color32) -> Self {
75 Self {
76 size,
77 source_size: Vec2::new(size[0] as f32, size[1] as f32),
78 pixels: vec![color; size[0] * size[1]],
79 }
80 }
81
82 pub fn from_rgba_unmultiplied(size: [usize; 2], rgba: &[u8]) -> Self {
113 assert_eq!(
114 size[0] * size[1] * 4,
115 rgba.len(),
116 "size: {:?}, rgba.len(): {}",
117 size,
118 rgba.len()
119 );
120 let pixels = rgba
121 .chunks_exact(4)
122 .map(|p| Color32::from_rgba_unmultiplied(p[0], p[1], p[2], p[3]))
123 .collect();
124 Self::new(size, pixels)
125 }
126
127 pub fn from_rgba_premultiplied(size: [usize; 2], rgba: &[u8]) -> Self {
128 assert_eq!(
129 size[0] * size[1] * 4,
130 rgba.len(),
131 "size: {:?}, rgba.len(): {}",
132 size,
133 rgba.len()
134 );
135 let pixels = rgba
136 .chunks_exact(4)
137 .map(|p| Color32::from_rgba_premultiplied(p[0], p[1], p[2], p[3]))
138 .collect();
139 Self::new(size, pixels)
140 }
141
142 pub fn from_gray(size: [usize; 2], gray: &[u8]) -> Self {
146 assert_eq!(
147 size[0] * size[1],
148 gray.len(),
149 "size: {:?}, gray.len(): {}",
150 size,
151 gray.len()
152 );
153 let pixels = gray.iter().map(|p| Color32::from_gray(*p)).collect();
154 Self::new(size, pixels)
155 }
156
157 #[doc(alias = "from_grey_iter")]
162 pub fn from_gray_iter(size: [usize; 2], gray_iter: impl Iterator<Item = u8>) -> Self {
163 let pixels: Vec<_> = gray_iter.map(Color32::from_gray).collect();
164 assert_eq!(
165 size[0] * size[1],
166 pixels.len(),
167 "size: {:?}, pixels.len(): {}",
168 size,
169 pixels.len()
170 );
171 Self::new(size, pixels)
172 }
173
174 #[cfg(feature = "bytemuck")]
176 pub fn as_raw(&self) -> &[u8] {
177 bytemuck::cast_slice(&self.pixels)
178 }
179
180 #[cfg(feature = "bytemuck")]
182 pub fn as_raw_mut(&mut self) -> &mut [u8] {
183 bytemuck::cast_slice_mut(&mut self.pixels)
184 }
185
186 pub fn from_rgb(size: [usize; 2], rgb: &[u8]) -> Self {
193 assert_eq!(
194 size[0] * size[1] * 3,
195 rgb.len(),
196 "size: {:?}, rgb.len(): {}",
197 size,
198 rgb.len()
199 );
200 let pixels = rgb
201 .chunks_exact(3)
202 .map(|p| Color32::from_rgb(p[0], p[1], p[2]))
203 .collect();
204 Self::new(size, pixels)
205 }
206
207 pub fn example() -> Self {
209 let width = 128;
210 let height = 64;
211 let mut img = Self::filled([width, height], Color32::TRANSPARENT);
212 for y in 0..height {
213 for x in 0..width {
214 let h = x as f32 / width as f32;
215 let s = 1.0;
216 let v = 1.0;
217 let a = y as f32 / height as f32;
218 img[(x, y)] = crate::Hsva { h, s, v, a }.into();
219 }
220 }
221 img
222 }
223
224 #[inline]
226 pub fn with_source_size(mut self, source_size: Vec2) -> Self {
227 self.source_size = source_size;
228 self
229 }
230
231 #[inline]
232 pub fn width(&self) -> usize {
233 self.size[0]
234 }
235
236 #[inline]
237 pub fn height(&self) -> usize {
238 self.size[1]
239 }
240
241 pub fn region(&self, region: &emath::Rect, pixels_per_point: Option<f32>) -> Self {
249 let pixels_per_point = pixels_per_point.unwrap_or(1.0);
250 let min_x = (region.min.x * pixels_per_point) as usize;
251 let max_x = (region.max.x * pixels_per_point) as usize;
252 let min_y = (region.min.y * pixels_per_point) as usize;
253 let max_y = (region.max.y * pixels_per_point) as usize;
254 assert!(
255 min_x <= max_x && min_y <= max_y,
256 "Screenshot region is invalid: {region:?}"
257 );
258 let width = max_x - min_x;
259 let height = max_y - min_y;
260 let mut output = Vec::with_capacity(width * height);
261 let row_stride = self.size[0];
262
263 for row in min_y..max_y {
264 output.extend_from_slice(
265 &self.pixels[row * row_stride + min_x..row * row_stride + max_x],
266 );
267 }
268 Self::new([width, height], output)
269 }
270
271 pub fn region_by_pixels(&self, [x, y]: [usize; 2], [w, h]: [usize; 2]) -> Self {
273 assert!(
274 x + w <= self.width(),
275 "x + w should be <= self.width(), but x: {}, w: {}, width: {}",
276 x,
277 w,
278 self.width()
279 );
280 assert!(
281 y + h <= self.height(),
282 "y + h should be <= self.height(), but y: {}, h: {}, height: {}",
283 y,
284 h,
285 self.height()
286 );
287
288 let mut pixels = Vec::with_capacity(w * h);
289 for y in y..y + h {
290 let offset = y * self.width() + x;
291 pixels.extend(&self.pixels[offset..(offset + w)]);
292 }
293 assert_eq!(
294 pixels.len(),
295 w * h,
296 "pixels.len should be w * h, but got {}",
297 pixels.len()
298 );
299 Self::new([w, h], pixels)
300 }
301}
302
303impl std::ops::Index<(usize, usize)> for ColorImage {
304 type Output = Color32;
305
306 #[inline]
307 fn index(&self, (x, y): (usize, usize)) -> &Color32 {
308 let [w, h] = self.size;
309 assert!(x < w && y < h, "x: {x}, y: {y}, w: {w}, h: {h}");
310 &self.pixels[y * w + x]
311 }
312}
313
314impl std::ops::IndexMut<(usize, usize)> for ColorImage {
315 #[inline]
316 fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Color32 {
317 let [w, h] = self.size;
318 assert!(x < w && y < h, "x: {x}, y: {y}, w: {w}, h: {h}");
319 &mut self.pixels[y * w + x]
320 }
321}
322
323impl From<ColorImage> for ImageData {
324 #[inline(always)]
325 fn from(image: ColorImage) -> Self {
326 Self::Color(Arc::new(image))
327 }
328}
329
330impl From<Arc<ColorImage>> for ImageData {
331 #[inline]
332 fn from(image: Arc<ColorImage>) -> Self {
333 Self::Color(image)
334 }
335}
336
337impl std::fmt::Debug for ColorImage {
338 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
339 f.debug_struct("ColorImage")
340 .field("size", &self.size)
341 .field("pixel-count", &self.pixels.len())
342 .finish_non_exhaustive()
343 }
344}
345
346#[derive(Clone, Copy, Debug, Default, PartialEq)]
355#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
356pub enum AlphaFromCoverage {
357 Linear,
363
364 Gamma(f32),
366
367 #[default]
374 TwoCoverageMinusCoverageSq,
375}
376
377impl AlphaFromCoverage {
378 pub const LIGHT_MODE_DEFAULT: Self = Self::Linear;
380
381 pub const DARK_MODE_DEFAULT: Self = Self::TwoCoverageMinusCoverageSq;
383
384 #[inline(always)]
386 pub fn alpha_from_coverage(&self, coverage: f32) -> f32 {
387 match self {
388 Self::Linear => coverage,
389 Self::Gamma(gamma) => coverage.powf(*gamma),
390 Self::TwoCoverageMinusCoverageSq => 2.0 * coverage - coverage * coverage,
391 }
392 }
393
394 #[inline(always)]
395 pub fn color_from_coverage(&self, coverage: f32) -> Color32 {
396 let alpha = self.alpha_from_coverage(coverage);
397 Color32::from_white_alpha(ecolor::linear_u8_from_linear_f32(alpha))
398 }
399}
400
401#[derive(Clone, PartialEq, Eq)]
407#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
408#[must_use = "The painter must take care of this"]
409pub struct ImageDelta {
410 pub image: ImageData,
416
417 pub options: TextureOptions,
418
419 pub pos: Option<[usize; 2]>,
423}
424
425impl ImageDelta {
426 pub fn full(image: impl Into<ImageData>, options: TextureOptions) -> Self {
428 Self {
429 image: image.into(),
430 options,
431 pos: None,
432 }
433 }
434
435 pub fn partial(pos: [usize; 2], image: impl Into<ImageData>, options: TextureOptions) -> Self {
437 Self {
438 image: image.into(),
439 options,
440 pos: Some(pos),
441 }
442 }
443
444 pub fn is_whole(&self) -> bool {
447 self.pos.is_none()
448 }
449}