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