1use alloc::vec;
8use alloc::vec::Vec;
9
10use core::convert::TryFrom;
11use core::num::NonZeroUsize;
12
13use tiny_skia_path::IntSize;
14
15use crate::{Color, IntRect};
16
17use crate::color::PremultipliedColorU8;
18use crate::geom::{IntSizeExt, ScreenIntRect};
19
20#[cfg(feature = "png-format")]
21use crate::color::{premultiply_u8, ALPHA_U8_OPAQUE};
22
23pub const BYTES_PER_PIXEL: usize = 4;
25
26#[derive(Clone, PartialEq)]
30pub struct Pixmap {
31 data: Vec<u8>,
32 size: IntSize,
33}
34
35impl Pixmap {
36 pub fn new(width: u32, height: u32) -> Option<Self> {
44 let size = IntSize::from_wh(width, height)?;
45 let data_len = data_len_for_size(size)?;
46
47 Some(Pixmap {
51 data: vec![0; data_len],
52 size,
53 })
54 }
55
56 pub fn from_vec(data: Vec<u8>, size: IntSize) -> Option<Self> {
63 let data_len = data_len_for_size(size)?;
64 if data.len() != data_len {
65 return None;
66 }
67
68 Some(Pixmap { data, size })
69 }
70
71 #[cfg(feature = "png-format")]
76 pub fn decode_png(data: &[u8]) -> Result<Self, png::DecodingError> {
77 fn make_custom_png_error(msg: &str) -> png::DecodingError {
78 std::io::Error::new(std::io::ErrorKind::Other, msg).into()
79 }
80
81 let mut decoder = png::Decoder::new(std::io::BufReader::new(std::io::Cursor::new(data)));
82 decoder.set_transformations(png::Transformations::normalize_to_color8());
83 let mut reader = decoder.read_info()?;
84 let output_buffer_size = reader
85 .output_buffer_size()
86 .ok_or(png::DecodingError::LimitsExceeded)?;
87 let mut img_data = vec![0; output_buffer_size];
88 let info = reader.next_frame(&mut img_data)?;
89
90 if info.bit_depth != png::BitDepth::Eight {
91 return Err(make_custom_png_error("unsupported bit depth"));
92 }
93
94 let size = IntSize::from_wh(info.width, info.height)
95 .ok_or_else(|| make_custom_png_error("invalid image size"))?;
96 let data_len =
97 data_len_for_size(size).ok_or_else(|| make_custom_png_error("image is too big"))?;
98
99 img_data = match info.color_type {
100 png::ColorType::Rgb => {
101 let mut rgba_data = Vec::with_capacity(data_len);
102 for rgb in img_data.chunks(3) {
103 rgba_data.push(rgb[0]);
104 rgba_data.push(rgb[1]);
105 rgba_data.push(rgb[2]);
106 rgba_data.push(ALPHA_U8_OPAQUE);
107 }
108
109 rgba_data
110 }
111 png::ColorType::Rgba => img_data,
112 png::ColorType::Grayscale => {
113 let mut rgba_data = Vec::with_capacity(data_len);
114 for gray in img_data {
115 rgba_data.push(gray);
116 rgba_data.push(gray);
117 rgba_data.push(gray);
118 rgba_data.push(ALPHA_U8_OPAQUE);
119 }
120
121 rgba_data
122 }
123 png::ColorType::GrayscaleAlpha => {
124 let mut rgba_data = Vec::with_capacity(data_len);
125 for slice in img_data.chunks(2) {
126 let gray = slice[0];
127 let alpha = slice[1];
128 rgba_data.push(gray);
129 rgba_data.push(gray);
130 rgba_data.push(gray);
131 rgba_data.push(alpha);
132 }
133
134 rgba_data
135 }
136 png::ColorType::Indexed => {
137 return Err(make_custom_png_error("indexed PNG is not supported"));
138 }
139 };
140
141 for pixel in img_data.as_mut_slice().chunks_mut(BYTES_PER_PIXEL) {
150 let a = pixel[3];
151 pixel[0] = premultiply_u8(pixel[0], a);
152 pixel[1] = premultiply_u8(pixel[1], a);
153 pixel[2] = premultiply_u8(pixel[2], a);
154 }
155
156 Pixmap::from_vec(img_data, size)
157 .ok_or_else(|| make_custom_png_error("failed to create a pixmap"))
158 }
159
160 #[cfg(feature = "png-format")]
165 pub fn load_png<P: AsRef<std::path::Path>>(path: P) -> Result<Self, png::DecodingError> {
166 let data = std::fs::read(path)?;
170 Self::decode_png(&data)
171 }
172
173 #[cfg(feature = "png-format")]
175 pub fn encode_png(&self) -> Result<Vec<u8>, png::EncodingError> {
176 self.as_ref().encode_png()
177 }
178
179 #[cfg(feature = "png-format")]
181 pub fn save_png<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), png::EncodingError> {
182 self.as_ref().save_png(path)
183 }
184
185 pub fn as_ref(&self) -> PixmapRef<'_> {
187 PixmapRef {
188 data: &self.data,
189 size: self.size,
190 }
191 }
192
193 pub fn as_mut(&mut self) -> PixmapMut<'_> {
195 PixmapMut {
196 data: &mut self.data,
197 size: self.size,
198 }
199 }
200
201 #[inline]
203 pub fn width(&self) -> u32 {
204 self.size.width()
205 }
206
207 #[inline]
209 pub fn height(&self) -> u32 {
210 self.size.height()
211 }
212
213 #[allow(dead_code)]
215 pub(crate) fn size(&self) -> IntSize {
216 self.size
217 }
218
219 pub fn fill(&mut self, color: Color) {
221 let c = color.premultiply().to_color_u8();
222 for p in self.as_mut().pixels_mut() {
223 *p = c;
224 }
225 }
226
227 pub fn data(&self) -> &[u8] {
231 self.data.as_slice()
232 }
233
234 pub fn data_mut(&mut self) -> &mut [u8] {
238 self.data.as_mut_slice()
239 }
240
241 pub fn pixel(&self, x: u32, y: u32) -> Option<PremultipliedColorU8> {
245 let idx = self.width().checked_mul(y)?.checked_add(x)?;
246 self.pixels().get(idx as usize).cloned()
247 }
248
249 pub fn pixels_mut(&mut self) -> &mut [PremultipliedColorU8] {
251 bytemuck::cast_slice_mut(self.data_mut())
252 }
253
254 pub fn pixels(&self) -> &[PremultipliedColorU8] {
256 bytemuck::cast_slice(self.data())
257 }
258
259 pub fn take(self) -> Vec<u8> {
263 self.data
264 }
265
266 pub fn take_demultiplied(mut self) -> Vec<u8> {
270 for pixel in self.pixels_mut() {
275 let c = pixel.demultiply();
276 *pixel =
277 PremultipliedColorU8::from_rgba_unchecked(c.red(), c.green(), c.blue(), c.alpha());
278 }
279 self.data
280 }
281
282 pub fn clone_rect(&self, rect: IntRect) -> Option<Pixmap> {
286 self.as_ref().clone_rect(rect)
287 }
288}
289
290impl core::fmt::Debug for Pixmap {
291 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
292 f.debug_struct("Pixmap")
293 .field("data", &"...")
294 .field("width", &self.size.width())
295 .field("height", &self.size.height())
296 .finish()
297 }
298}
299
300#[derive(Clone, Copy, PartialEq)]
306pub struct PixmapRef<'a> {
307 data: &'a [u8],
308 size: IntSize,
309}
310
311impl<'a> PixmapRef<'a> {
312 pub fn from_bytes(data: &'a [u8], width: u32, height: u32) -> Option<Self> {
319 let size = IntSize::from_wh(width, height)?;
320 let data_len = data_len_for_size(size)?;
321 if data.len() < data_len {
322 return None;
323 }
324
325 Some(PixmapRef { data, size })
326 }
327
328 pub fn to_owned(&self) -> Pixmap {
332 Pixmap {
333 data: self.data.to_vec(),
334 size: self.size,
335 }
336 }
337
338 #[inline]
340 pub fn width(&self) -> u32 {
341 self.size.width()
342 }
343
344 #[inline]
346 pub fn height(&self) -> u32 {
347 self.size.height()
348 }
349
350 pub(crate) fn size(&self) -> IntSize {
352 self.size
353 }
354
355 pub(crate) fn rect(&self) -> ScreenIntRect {
357 self.size.to_screen_int_rect(0, 0)
358 }
359
360 pub fn data(&self) -> &'a [u8] {
364 self.data
365 }
366
367 pub fn pixel(&self, x: u32, y: u32) -> Option<PremultipliedColorU8> {
371 let idx = self.width().checked_mul(y)?.checked_add(x)?;
372 self.pixels().get(idx as usize).cloned()
373 }
374
375 pub fn pixels(&self) -> &'a [PremultipliedColorU8] {
377 bytemuck::cast_slice(self.data())
378 }
379
380 pub fn clone_rect(&self, rect: IntRect) -> Option<Pixmap> {
386 let rect = self.rect().to_int_rect().intersect(&rect)?;
389 let mut new = Pixmap::new(rect.width(), rect.height())?;
390 {
391 let old_pixels = self.pixels();
392 let mut new_mut = new.as_mut();
393 let new_pixels = new_mut.pixels_mut();
394
395 for y in 0..rect.height() {
397 for x in 0..rect.width() {
398 let old_idx = (y + rect.y() as u32) * self.width() + (x + rect.x() as u32);
399 let new_idx = y * rect.width() + x;
400 new_pixels[new_idx as usize] = old_pixels[old_idx as usize];
401 }
402 }
403 }
404
405 Some(new)
406 }
407
408 #[cfg(feature = "png-format")]
410 pub fn encode_png(&self) -> Result<Vec<u8>, png::EncodingError> {
411 let demultiplied_data = self.to_owned().take_demultiplied();
417
418 let mut data = Vec::new();
419 {
420 let mut encoder = png::Encoder::new(&mut data, self.width(), self.height());
421 encoder.set_color(png::ColorType::Rgba);
422 encoder.set_depth(png::BitDepth::Eight);
423 let mut writer = encoder.write_header()?;
424 writer.write_image_data(&demultiplied_data)?;
425 }
426
427 Ok(data)
428 }
429
430 #[cfg(feature = "png-format")]
432 pub fn save_png<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), png::EncodingError> {
433 let data = self.encode_png()?;
434 std::fs::write(path, data)?;
435 Ok(())
436 }
437}
438
439impl core::fmt::Debug for PixmapRef<'_> {
440 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
441 f.debug_struct("PixmapRef")
442 .field("data", &"...")
443 .field("width", &self.size.width())
444 .field("height", &self.size.height())
445 .finish()
446 }
447}
448
449#[derive(PartialEq)]
455pub struct PixmapMut<'a> {
456 data: &'a mut [u8],
457 size: IntSize,
458}
459
460impl<'a> PixmapMut<'a> {
461 pub fn from_bytes(data: &'a mut [u8], width: u32, height: u32) -> Option<Self> {
468 let size = IntSize::from_wh(width, height)?;
469 let data_len = data_len_for_size(size)?;
470 if data.len() < data_len {
471 return None;
472 }
473
474 Some(PixmapMut { data, size })
475 }
476
477 pub fn to_owned(&self) -> Pixmap {
481 Pixmap {
482 data: self.data.to_vec(),
483 size: self.size,
484 }
485 }
486
487 pub fn as_ref(&self) -> PixmapRef<'_> {
489 PixmapRef {
490 data: self.data,
491 size: self.size,
492 }
493 }
494
495 #[inline]
497 pub fn width(&self) -> u32 {
498 self.size.width()
499 }
500
501 #[inline]
503 pub fn height(&self) -> u32 {
504 self.size.height()
505 }
506
507 pub(crate) fn size(&self) -> IntSize {
509 self.size
510 }
511
512 pub fn fill(&mut self, color: Color) {
514 let c = color.premultiply().to_color_u8();
515 for p in self.pixels_mut() {
516 *p = c;
517 }
518 }
519
520 pub fn data_mut(&mut self) -> &mut [u8] {
524 self.data
525 }
526
527 pub fn pixels_mut(&mut self) -> &mut [PremultipliedColorU8] {
529 bytemuck::cast_slice_mut(self.data_mut())
530 }
531
532 pub(crate) fn as_subpixmap(&mut self) -> SubPixmapMut<'_> {
534 SubPixmapMut {
535 size: self.size(),
536 real_width: self.width() as usize,
537 data: self.data,
538 }
539 }
540
541 pub(crate) fn subpixmap(&mut self, rect: IntRect) -> Option<SubPixmapMut<'_>> {
545 let rect = self.size.to_int_rect(0, 0).intersect(&rect)?;
546 let row_bytes = self.width() as usize * BYTES_PER_PIXEL;
547 let offset = rect.top() as usize * row_bytes + rect.left() as usize * BYTES_PER_PIXEL;
548
549 Some(SubPixmapMut {
550 size: rect.size(),
551 real_width: self.width() as usize,
552 data: &mut self.data[offset..],
553 })
554 }
555}
556
557impl core::fmt::Debug for PixmapMut<'_> {
558 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
559 f.debug_struct("PixmapMut")
560 .field("data", &"...")
561 .field("width", &self.size.width())
562 .field("height", &self.size.height())
563 .finish()
564 }
565}
566
567pub struct SubPixmapMut<'a> {
578 pub data: &'a mut [u8],
579 pub size: IntSize,
580 pub real_width: usize,
581}
582
583impl SubPixmapMut<'_> {
584 pub fn pixels_mut(&mut self) -> &mut [PremultipliedColorU8] {
586 bytemuck::cast_slice_mut(self.data)
587 }
588}
589
590fn min_row_bytes(size: IntSize) -> Option<NonZeroUsize> {
594 let w = i32::try_from(size.width()).ok()?;
595 let w = w.checked_mul(BYTES_PER_PIXEL as i32)?;
596 NonZeroUsize::new(w as usize)
597}
598
599fn compute_data_len(size: IntSize, row_bytes: usize) -> Option<usize> {
601 let h = size.height().checked_sub(1)?;
602 let h = (h as usize).checked_mul(row_bytes)?;
603
604 let w = (size.width() as usize).checked_mul(BYTES_PER_PIXEL)?;
605
606 h.checked_add(w)
607}
608
609fn data_len_for_size(size: IntSize) -> Option<usize> {
610 let row_bytes = min_row_bytes(size)?;
611 compute_data_len(size, row_bytes.get())
612}