1// Copyright 2006 The Android Open Source Project
2// Copyright 2020 Yevhenii Reizner
3//
4// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6
7use 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
23/// Number of bytes per pixel.
24pub const BYTES_PER_PIXEL: usize = 4;
25
26/// A container that owns premultiplied RGBA pixels.
27///
28/// The data is not aligned, therefore width == stride.
29#[derive(Clone, PartialEq)]
30pub struct Pixmap {
31 data: Vec<u8>,
32 size: IntSize,
33}
34
35impl Pixmap {
36 /// Allocates a new pixmap.
37 ///
38 /// A pixmap is filled with transparent black by default, aka (0, 0, 0, 0).
39 ///
40 /// Zero size in an error.
41 ///
42 /// Pixmap's width is limited by i32::MAX/4.
43 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 // We cannot check that allocation was successful yet.
48 // We have to wait for https://github.com/rust-lang/rust/issues/48043
49
50 Some(Pixmap {
51 data: vec![0; data_len],
52 size,
53 })
54 }
55
56 /// Creates a new pixmap by taking ownership over an image buffer
57 /// (premultiplied RGBA pixels).
58 ///
59 /// The size needs to match the data provided.
60 ///
61 /// Pixmap's width is limited by i32::MAX/4.
62 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 /// Decodes a PNG data into a `Pixmap`.
72 ///
73 /// Only 8-bit images are supported.
74 /// Index PNGs are not supported.
75 #[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 // Premultiply alpha.
139 //
140 // We cannon use RasterPipeline here, which is faster,
141 // because it produces slightly different results.
142 // Seems like Skia does the same.
143 //
144 // Also, in our tests unsafe version (no bound checking)
145 // had roughly the same performance. So we keep the safe one.
146 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 /// Loads a PNG file into a `Pixmap`.
158 ///
159 /// Only 8-bit images are supported.
160 /// Index PNGs are not supported.
161 #[cfg(feature = "png-format")]
162 pub fn load_png<P: AsRef<std::path::Path>>(path: P) -> Result<Self, png::DecodingError> {
163 // `png::Decoder` is generic over input, which means that it will instance
164 // two copies: one for `&[]` and one for `File`. Which will simply bloat the code.
165 // Therefore we're using only one type for input.
166 let data = std::fs::read(path)?;
167 Self::decode_png(&data)
168 }
169
170 /// Encodes pixmap into a PNG data.
171 #[cfg(feature = "png-format")]
172 pub fn encode_png(&self) -> Result<Vec<u8>, png::EncodingError> {
173 self.as_ref().encode_png()
174 }
175
176 /// Saves pixmap as a PNG file.
177 #[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 /// Returns a container that references Pixmap's data.
183 pub fn as_ref(&self) -> PixmapRef {
184 PixmapRef {
185 data: &self.data,
186 size: self.size,
187 }
188 }
189
190 /// Returns a container that references Pixmap's data.
191 pub fn as_mut(&mut self) -> PixmapMut {
192 PixmapMut {
193 data: &mut self.data,
194 size: self.size,
195 }
196 }
197
198 /// Returns pixmap's width.
199 #[inline]
200 pub fn width(&self) -> u32 {
201 self.size.width()
202 }
203
204 /// Returns pixmap's height.
205 #[inline]
206 pub fn height(&self) -> u32 {
207 self.size.height()
208 }
209
210 /// Returns pixmap's size.
211 #[allow(dead_code)]
212 pub(crate) fn size(&self) -> IntSize {
213 self.size
214 }
215
216 /// Fills the entire pixmap with a specified color.
217 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 /// Returns the internal data.
225 ///
226 /// Byteorder: RGBA
227 pub fn data(&self) -> &[u8] {
228 self.data.as_slice()
229 }
230
231 /// Returns the mutable internal data.
232 ///
233 /// Byteorder: RGBA
234 pub fn data_mut(&mut self) -> &mut [u8] {
235 self.data.as_mut_slice()
236 }
237
238 /// Returns a pixel color.
239 ///
240 /// Returns `None` when position is out of bounds.
241 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 /// Returns a mutable slice of pixels.
247 pub fn pixels_mut(&mut self) -> &mut [PremultipliedColorU8] {
248 bytemuck::cast_slice_mut(self.data_mut())
249 }
250
251 /// Returns a slice of pixels.
252 pub fn pixels(&self) -> &[PremultipliedColorU8] {
253 bytemuck::cast_slice(self.data())
254 }
255
256 /// Consumes the internal data.
257 ///
258 /// Byteorder: RGBA
259 pub fn take(self) -> Vec<u8> {
260 self.data
261 }
262
263 /// Returns a copy of the pixmap that intersects the `rect`.
264 ///
265 /// Returns `None` when `Pixmap`'s rect doesn't contain `rect`.
266 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&mut DebugStruct<'_, '_>.debug_struct("Pixmap")
274 .field("data", &"...")
275 .field("width", &self.size.width())
276 .field(name:"height", &self.size.height())
277 .finish()
278 }
279}
280
281/// A container that references premultiplied RGBA pixels.
282///
283/// Can be created from `Pixmap` or from a user provided data.
284///
285/// The data is not aligned, therefore width == stride.
286#[derive(Clone, Copy, PartialEq)]
287pub struct PixmapRef<'a> {
288 data: &'a [u8],
289 size: IntSize,
290}
291
292impl<'a> PixmapRef<'a> {
293 /// Creates a new `PixmapRef` from bytes.
294 ///
295 /// The size must be at least `size.width() * size.height() * BYTES_PER_PIXEL`.
296 /// Zero size in an error. Width is limited by i32::MAX/4.
297 ///
298 /// The `data` is assumed to have premultiplied RGBA pixels (byteorder: RGBA).
299 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 /// Creates a new `Pixmap` from the current data.
310 ///
311 /// Clones the underlying data.
312 pub fn to_owned(&self) -> Pixmap {
313 Pixmap {
314 data: self.data.to_vec(),
315 size: self.size,
316 }
317 }
318
319 /// Returns pixmap's width.
320 #[inline]
321 pub fn width(&self) -> u32 {
322 self.size.width()
323 }
324
325 /// Returns pixmap's height.
326 #[inline]
327 pub fn height(&self) -> u32 {
328 self.size.height()
329 }
330
331 /// Returns pixmap's size.
332 pub(crate) fn size(&self) -> IntSize {
333 self.size
334 }
335
336 /// Returns pixmap's rect.
337 pub(crate) fn rect(&self) -> ScreenIntRect {
338 self.size.to_screen_int_rect(0, 0)
339 }
340
341 /// Returns the internal data.
342 ///
343 /// Byteorder: RGBA
344 pub fn data(&self) -> &'a [u8] {
345 self.data
346 }
347
348 /// Returns a pixel color.
349 ///
350 /// Returns `None` when position is out of bounds.
351 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 /// Returns a slice of pixels.
357 pub fn pixels(&self) -> &'a [PremultipliedColorU8] {
358 bytemuck::cast_slice(self.data())
359 }
360
361 // TODO: add rows() iterator
362
363 /// Returns a copy of the pixmap that intersects the `rect`.
364 ///
365 /// Returns `None` when `Pixmap`'s rect doesn't contain `rect`.
366 pub fn clone_rect(&self, rect: IntRect) -> Option<Pixmap> {
367 // TODO: to ScreenIntRect?
368
369 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 // TODO: optimize
377 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 /// Encodes pixmap into a PNG data.
390 #[cfg(feature = "png-format")]
391 pub fn encode_png(&self) -> Result<Vec<u8>, png::EncodingError> {
392 // Skia uses skcms here, which is somewhat similar to RasterPipeline.
393
394 // Sadly, we have to copy the pixmap here, because of demultiplication.
395 // Not sure how to avoid this.
396 // TODO: remove allocation
397 let mut tmp_pixmap = self.to_owned();
398
399 // Demultiply alpha.
400 //
401 // RasterPipeline is 15% faster here, but produces slightly different results
402 // due to rounding. So we stick with this method for now.
403 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 /// Saves pixmap as a PNG file.
422 #[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&mut DebugStruct<'_, '_>.debug_struct("PixmapRef")
433 .field("data", &"...")
434 .field("width", &self.size.width())
435 .field(name:"height", &self.size.height())
436 .finish()
437 }
438}
439
440/// A container that references mutable premultiplied RGBA pixels.
441///
442/// Can be created from `Pixmap` or from a user provided data.
443///
444/// The data is not aligned, therefore width == stride.
445#[derive(PartialEq)]
446pub struct PixmapMut<'a> {
447 data: &'a mut [u8],
448 size: IntSize,
449}
450
451impl<'a> PixmapMut<'a> {
452 /// Creates a new `PixmapMut` from bytes.
453 ///
454 /// The size must be at least `size.width() * size.height() * BYTES_PER_PIXEL`.
455 /// Zero size in an error. Width is limited by i32::MAX/4.
456 ///
457 /// The `data` is assumed to have premultiplied RGBA pixels (byteorder: RGBA).
458 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 /// Creates a new `Pixmap` from the current data.
469 ///
470 /// Clones the underlying data.
471 pub fn to_owned(&self) -> Pixmap {
472 Pixmap {
473 data: self.data.to_vec(),
474 size: self.size,
475 }
476 }
477
478 /// Returns a container that references Pixmap's data.
479 pub fn as_ref(&self) -> PixmapRef {
480 PixmapRef {
481 data: self.data,
482 size: self.size,
483 }
484 }
485
486 /// Returns pixmap's width.
487 #[inline]
488 pub fn width(&self) -> u32 {
489 self.size.width()
490 }
491
492 /// Returns pixmap's height.
493 #[inline]
494 pub fn height(&self) -> u32 {
495 self.size.height()
496 }
497
498 /// Returns pixmap's size.
499 pub(crate) fn size(&self) -> IntSize {
500 self.size
501 }
502
503 /// Fills the entire pixmap with a specified color.
504 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 /// Returns the mutable internal data.
512 ///
513 /// Byteorder: RGBA
514 pub fn data_mut(&mut self) -> &mut [u8] {
515 self.data
516 }
517
518 /// Returns a mutable slice of pixels.
519 pub fn pixels_mut(&mut self) -> &mut [PremultipliedColorU8] {
520 bytemuck::cast_slice_mut(self.data_mut())
521 }
522
523 /// Creates `SubPixmapMut` that contains the whole `PixmapMut`.
524 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 /// Returns a mutable reference to the pixmap region that intersects the `rect`.
533 ///
534 /// Returns `None` when `Pixmap`'s rect doesn't contain `rect`.
535 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&mut DebugStruct<'_, '_>.debug_struct("PixmapMut")
551 .field("data", &"...")
552 .field("width", &self.size.width())
553 .field(name:"height", &self.size.height())
554 .finish()
555 }
556}
557
558/// A `PixmapMut` subregion.
559///
560/// Unlike `PixmapMut`, contains `real_width` which references the parent `PixmapMut` width.
561/// This way we can operate on a `PixmapMut` subregion without reallocations.
562/// Primarily required because of `DrawTiler`.
563///
564/// We cannot implement it in `PixmapMut` directly, because it will brake `fill`, `data_mut`
565/// `pixels_mut` and other similar methods.
566/// This is because `SubPixmapMut.data` references more "data" than it actually allowed to access.
567/// On the other hand, `PixmapMut.data` can access all it's data and it's stored linearly.
568pub 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 /// Returns a mutable slice of pixels.
576 pub fn pixels_mut(&mut self) -> &mut [PremultipliedColorU8] {
577 bytemuck::cast_slice_mut(self.data)
578 }
579}
580
581/// Returns minimum bytes per row as usize.
582///
583/// Pixmap's maximum value for row bytes must fit in 31 bits.
584fn min_row_bytes(size: IntSize) -> Option<NonZeroUsize> {
585 let w: i32 = i32::try_from(size.width()).ok()?;
586 let w: i32 = w.checked_mul(BYTES_PER_PIXEL as i32)?;
587 NonZeroUsize::new(w as usize)
588}
589
590/// Returns storage size required by pixel array.
591fn compute_data_len(size: IntSize, row_bytes: usize) -> Option<usize> {
592 let h: u32 = size.height().checked_sub(1)?;
593 let h: usize = (h as usize).checked_mul(row_bytes)?;
594
595 let w: usize = (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: NonZero = min_row_bytes(size)?;
602 compute_data_len(size, row_bytes:row_bytes.get())
603}
604