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(data);
82        decoder.set_transformations(png::Transformations::normalize_to_color8());
83        let mut reader = decoder.read_info()?;
84        let mut img_data = vec![0; reader.output_buffer_size()];
85        let info = reader.next_frame(&mut img_data)?;
86
87        if info.bit_depth != png::BitDepth::Eight {
88            return Err(make_custom_png_error("unsupported bit depth"));
89        }
90
91        let size = IntSize::from_wh(info.width, info.height)
92            .ok_or_else(|| make_custom_png_error("invalid image size"))?;
93        let data_len =
94            data_len_for_size(size).ok_or_else(|| make_custom_png_error("image is too big"))?;
95
96        img_data = match info.color_type {
97            png::ColorType::Rgb => {
98                let mut rgba_data = Vec::with_capacity(data_len);
99                for rgb in img_data.chunks(3) {
100                    rgba_data.push(rgb[0]);
101                    rgba_data.push(rgb[1]);
102                    rgba_data.push(rgb[2]);
103                    rgba_data.push(ALPHA_U8_OPAQUE);
104                }
105
106                rgba_data
107            }
108            png::ColorType::Rgba => img_data,
109            png::ColorType::Grayscale => {
110                let mut rgba_data = Vec::with_capacity(data_len);
111                for gray in img_data {
112                    rgba_data.push(gray);
113                    rgba_data.push(gray);
114                    rgba_data.push(gray);
115                    rgba_data.push(ALPHA_U8_OPAQUE);
116                }
117
118                rgba_data
119            }
120            png::ColorType::GrayscaleAlpha => {
121                let mut rgba_data = Vec::with_capacity(data_len);
122                for slice in img_data.chunks(2) {
123                    let gray = slice[0];
124                    let alpha = slice[1];
125                    rgba_data.push(gray);
126                    rgba_data.push(gray);
127                    rgba_data.push(gray);
128                    rgba_data.push(alpha);
129                }
130
131                rgba_data
132            }
133            png::ColorType::Indexed => {
134                return Err(make_custom_png_error("indexed PNG is not supported"));
135            }
136        };
137
138        for pixel in img_data.as_mut_slice().chunks_mut(BYTES_PER_PIXEL) {
147            let a = pixel[3];
148            pixel[0] = premultiply_u8(pixel[0], a);
149            pixel[1] = premultiply_u8(pixel[1], a);
150            pixel[2] = premultiply_u8(pixel[2], a);
151        }
152
153        Pixmap::from_vec(img_data, size)
154            .ok_or_else(|| make_custom_png_error("failed to create a pixmap"))
155    }
156
157    #[cfg(feature = "png-format")]
162    pub fn load_png<P: AsRef<std::path::Path>>(path: P) -> Result<Self, png::DecodingError> {
163        let data = std::fs::read(path)?;
167        Self::decode_png(&data)
168    }
169
170    #[cfg(feature = "png-format")]
172    pub fn encode_png(&self) -> Result<Vec<u8>, png::EncodingError> {
173        self.as_ref().encode_png()
174    }
175
176    #[cfg(feature = "png-format")]
178    pub fn save_png<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), png::EncodingError> {
179        self.as_ref().save_png(path)
180    }
181
182    pub fn as_ref(&self) -> PixmapRef {
184        PixmapRef {
185            data: &self.data,
186            size: self.size,
187        }
188    }
189
190    pub fn as_mut(&mut self) -> PixmapMut {
192        PixmapMut {
193            data: &mut self.data,
194            size: self.size,
195        }
196    }
197
198    #[inline]
200    pub fn width(&self) -> u32 {
201        self.size.width()
202    }
203
204    #[inline]
206    pub fn height(&self) -> u32 {
207        self.size.height()
208    }
209
210    #[allow(dead_code)]
212    pub(crate) fn size(&self) -> IntSize {
213        self.size
214    }
215
216    pub fn fill(&mut self, color: Color) {
218        let c = color.premultiply().to_color_u8();
219        for p in self.as_mut().pixels_mut() {
220            *p = c;
221        }
222    }
223
224    pub fn data(&self) -> &[u8] {
228        self.data.as_slice()
229    }
230
231    pub fn data_mut(&mut self) -> &mut [u8] {
235        self.data.as_mut_slice()
236    }
237
238    pub fn pixel(&self, x: u32, y: u32) -> Option<PremultipliedColorU8> {
242        let idx = self.width().checked_mul(y)?.checked_add(x)?;
243        self.pixels().get(idx as usize).cloned()
244    }
245
246    pub fn pixels_mut(&mut self) -> &mut [PremultipliedColorU8] {
248        bytemuck::cast_slice_mut(self.data_mut())
249    }
250
251    pub fn pixels(&self) -> &[PremultipliedColorU8] {
253        bytemuck::cast_slice(self.data())
254    }
255
256    pub fn take(self) -> Vec<u8> {
260        self.data
261    }
262
263    pub fn clone_rect(&self, rect: IntRect) -> Option<Pixmap> {
267        self.as_ref().clone_rect(rect)
268    }
269}
270
271impl core::fmt::Debug for Pixmap {
272    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
273        f.debug_struct("Pixmap")
274            .field("data", &"...")
275            .field("width", &self.size.width())
276            .field("height", &self.size.height())
277            .finish()
278    }
279}
280
281#[derive(Clone, Copy, PartialEq)]
287pub struct PixmapRef<'a> {
288    data: &'a [u8],
289    size: IntSize,
290}
291
292impl<'a> PixmapRef<'a> {
293    pub fn from_bytes(data: &'a [u8], width: u32, height: u32) -> Option<Self> {
300        let size = IntSize::from_wh(width, height)?;
301        let data_len = data_len_for_size(size)?;
302        if data.len() < data_len {
303            return None;
304        }
305
306        Some(PixmapRef { data, size })
307    }
308
309    pub fn to_owned(&self) -> Pixmap {
313        Pixmap {
314            data: self.data.to_vec(),
315            size: self.size,
316        }
317    }
318
319    #[inline]
321    pub fn width(&self) -> u32 {
322        self.size.width()
323    }
324
325    #[inline]
327    pub fn height(&self) -> u32 {
328        self.size.height()
329    }
330
331    pub(crate) fn size(&self) -> IntSize {
333        self.size
334    }
335
336    pub(crate) fn rect(&self) -> ScreenIntRect {
338        self.size.to_screen_int_rect(0, 0)
339    }
340
341    pub fn data(&self) -> &'a [u8] {
345        self.data
346    }
347
348    pub fn pixel(&self, x: u32, y: u32) -> Option<PremultipliedColorU8> {
352        let idx = self.width().checked_mul(y)?.checked_add(x)?;
353        self.pixels().get(idx as usize).cloned()
354    }
355
356    pub fn pixels(&self) -> &'a [PremultipliedColorU8] {
358        bytemuck::cast_slice(self.data())
359    }
360
361    pub fn clone_rect(&self, rect: IntRect) -> Option<Pixmap> {
367        let rect = self.rect().to_int_rect().intersect(&rect)?;
370        let mut new = Pixmap::new(rect.width(), rect.height())?;
371        {
372            let old_pixels = self.pixels();
373            let mut new_mut = new.as_mut();
374            let new_pixels = new_mut.pixels_mut();
375
376            for y in 0..rect.height() {
378                for x in 0..rect.width() {
379                    let old_idx = (y + rect.y() as u32) * self.width() + (x + rect.x() as u32);
380                    let new_idx = y * rect.width() + x;
381                    new_pixels[new_idx as usize] = old_pixels[old_idx as usize];
382                }
383            }
384        }
385
386        Some(new)
387    }
388
389    #[cfg(feature = "png-format")]
391    pub fn encode_png(&self) -> Result<Vec<u8>, png::EncodingError> {
392        let mut tmp_pixmap = self.to_owned();
398
399        for pixel in tmp_pixmap.pixels_mut() {
404            let c = pixel.demultiply();
405            *pixel =
406                PremultipliedColorU8::from_rgba_unchecked(c.red(), c.green(), c.blue(), c.alpha());
407        }
408
409        let mut data = Vec::new();
410        {
411            let mut encoder = png::Encoder::new(&mut data, self.width(), self.height());
412            encoder.set_color(png::ColorType::Rgba);
413            encoder.set_depth(png::BitDepth::Eight);
414            let mut writer = encoder.write_header()?;
415            writer.write_image_data(&tmp_pixmap.data)?;
416        }
417
418        Ok(data)
419    }
420
421    #[cfg(feature = "png-format")]
423    pub fn save_png<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), png::EncodingError> {
424        let data = self.encode_png()?;
425        std::fs::write(path, data)?;
426        Ok(())
427    }
428}
429
430impl core::fmt::Debug for PixmapRef<'_> {
431    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
432        f.debug_struct("PixmapRef")
433            .field("data", &"...")
434            .field("width", &self.size.width())
435            .field("height", &self.size.height())
436            .finish()
437    }
438}
439
440#[derive(PartialEq)]
446pub struct PixmapMut<'a> {
447    data: &'a mut [u8],
448    size: IntSize,
449}
450
451impl<'a> PixmapMut<'a> {
452    pub fn from_bytes(data: &'a mut [u8], width: u32, height: u32) -> Option<Self> {
459        let size = IntSize::from_wh(width, height)?;
460        let data_len = data_len_for_size(size)?;
461        if data.len() < data_len {
462            return None;
463        }
464
465        Some(PixmapMut { data, size })
466    }
467
468    pub fn to_owned(&self) -> Pixmap {
472        Pixmap {
473            data: self.data.to_vec(),
474            size: self.size,
475        }
476    }
477
478    pub fn as_ref(&self) -> PixmapRef {
480        PixmapRef {
481            data: self.data,
482            size: self.size,
483        }
484    }
485
486    #[inline]
488    pub fn width(&self) -> u32 {
489        self.size.width()
490    }
491
492    #[inline]
494    pub fn height(&self) -> u32 {
495        self.size.height()
496    }
497
498    pub(crate) fn size(&self) -> IntSize {
500        self.size
501    }
502
503    pub fn fill(&mut self, color: Color) {
505        let c = color.premultiply().to_color_u8();
506        for p in self.pixels_mut() {
507            *p = c;
508        }
509    }
510
511    pub fn data_mut(&mut self) -> &mut [u8] {
515        self.data
516    }
517
518    pub fn pixels_mut(&mut self) -> &mut [PremultipliedColorU8] {
520        bytemuck::cast_slice_mut(self.data_mut())
521    }
522
523    pub(crate) fn as_subpixmap(&mut self) -> SubPixmapMut {
525        SubPixmapMut {
526            size: self.size(),
527            real_width: self.width() as usize,
528            data: self.data,
529        }
530    }
531
532    pub(crate) fn subpixmap(&mut self, rect: IntRect) -> Option<SubPixmapMut> {
536        let rect = self.size.to_int_rect(0, 0).intersect(&rect)?;
537        let row_bytes = self.width() as usize * BYTES_PER_PIXEL;
538        let offset = rect.top() as usize * row_bytes + rect.left() as usize * BYTES_PER_PIXEL;
539
540        Some(SubPixmapMut {
541            size: rect.size(),
542            real_width: self.width() as usize,
543            data: &mut self.data[offset..],
544        })
545    }
546}
547
548impl core::fmt::Debug for PixmapMut<'_> {
549    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
550        f.debug_struct("PixmapMut")
551            .field("data", &"...")
552            .field("width", &self.size.width())
553            .field("height", &self.size.height())
554            .finish()
555    }
556}
557
558pub struct SubPixmapMut<'a> {
569    pub data: &'a mut [u8],
570    pub size: IntSize,
571    pub real_width: usize,
572}
573
574impl<'a> SubPixmapMut<'a> {
575    pub fn pixels_mut(&mut self) -> &mut [PremultipliedColorU8] {
577        bytemuck::cast_slice_mut(self.data)
578    }
579}
580
581fn min_row_bytes(size: IntSize) -> Option<NonZeroUsize> {
585    let w = i32::try_from(size.width()).ok()?;
586    let w = w.checked_mul(BYTES_PER_PIXEL as i32)?;
587    NonZeroUsize::new(w as usize)
588}
589
590fn compute_data_len(size: IntSize, row_bytes: usize) -> Option<usize> {
592    let h = size.height().checked_sub(1)?;
593    let h = (h as usize).checked_mul(row_bytes)?;
594
595    let w = (size.width() as usize).checked_mul(BYTES_PER_PIXEL)?;
596
597    h.checked_add(w)
598}
599
600fn data_len_for_size(size: IntSize) -> Option<usize> {
601    let row_bytes = min_row_bytes(size)?;
602    compute_data_len(size, row_bytes.get())
603}