1#[cfg(all(not(feature = "std"), feature = "no-std-float"))]
7use tiny_skia_path::NoStdFloat;
8
9use alloc::vec;
10use alloc::vec::Vec;
11
12use tiny_skia_path::{IntRect, IntSize, Path, Scalar, Transform};
13
14use crate::geom::IntSizeExt;
15use crate::painter::DrawTiler;
16use crate::pipeline::RasterPipelineBlitter;
17use crate::pixmap::SubPixmapMut;
18use crate::scan;
19use crate::{FillRule, PixmapRef};
20
21#[derive(Clone, Copy, PartialEq, Debug)]
23pub enum MaskType {
24 Alpha,
26 Luminance,
30}
31
32#[derive(Clone, PartialEq)]
41pub struct Mask {
42 data: Vec<u8>,
43 size: IntSize,
44}
45
46impl Mask {
47 pub fn new(width: u32, height: u32) -> Option<Self> {
49 let size = IntSize::from_wh(width, height)?;
50 Some(Mask {
51 data: vec![0; width as usize * height as usize],
52 size,
53 })
54 }
55
56 pub fn from_pixmap(pixmap: PixmapRef, mask_type: MaskType) -> Self {
58 let data_len = pixmap.width() as usize * pixmap.height() as usize;
59 let mut mask = Mask {
60 data: vec![0; data_len],
61 size: pixmap.size(),
62 };
63
64 match mask_type {
66 MaskType::Alpha => {
67 for (p, a) in pixmap.pixels().iter().zip(mask.data.as_mut_slice()) {
68 *a = p.alpha();
69 }
70 }
71 MaskType::Luminance => {
72 for (p, ma) in pixmap.pixels().iter().zip(mask.data.as_mut_slice()) {
73 let mut r = f32::from(p.red()) / 255.0;
75 let mut g = f32::from(p.green()) / 255.0;
76 let mut b = f32::from(p.blue()) / 255.0;
77 let a = f32::from(p.alpha()) / 255.0;
78
79 if p.alpha() != 0 {
81 r /= a;
82 g /= a;
83 b /= a;
84 }
85
86 let luma = r * 0.2126 + g * 0.7152 + b * 0.0722;
87 *ma = ((luma * a) * 255.0).clamp(0.0, 255.0).ceil() as u8;
88 }
89 }
90 }
91
92 mask
93 }
94
95 pub fn from_vec(data: Vec<u8>, size: IntSize) -> Option<Self> {
99 let data_len = size.width() as usize * size.height() as usize;
100 if data.len() != data_len {
101 return None;
102 }
103
104 Some(Mask { data, size })
105 }
106
107 #[inline]
109 pub fn width(&self) -> u32 {
110 self.size.width()
111 }
112
113 #[inline]
115 pub fn height(&self) -> u32 {
116 self.size.height()
117 }
118
119 #[allow(dead_code)]
121 pub(crate) fn size(&self) -> IntSize {
122 self.size
123 }
124
125 pub fn data(&self) -> &[u8] {
127 self.data.as_slice()
128 }
129
130 pub fn data_mut(&mut self) -> &mut [u8] {
132 self.data.as_mut_slice()
133 }
134
135 pub fn take(self) -> Vec<u8> {
137 self.data
138 }
139
140 pub(crate) fn as_submask(&self) -> SubMaskRef<'_> {
141 SubMaskRef {
142 size: self.size,
143 real_width: self.size.width(),
144 data: &self.data,
145 }
146 }
147
148 pub(crate) fn submask(&self, rect: IntRect) -> Option<SubMaskRef<'_>> {
149 let rect = self.size.to_int_rect(0, 0).intersect(&rect)?;
150 let row_bytes = self.width() as usize;
151 let offset = rect.top() as usize * row_bytes + rect.left() as usize;
152
153 Some(SubMaskRef {
154 size: rect.size(),
155 real_width: self.size.width(),
156 data: &self.data[offset..],
157 })
158 }
159
160 pub(crate) fn as_subpixmap(&mut self) -> SubPixmapMut<'_> {
161 SubPixmapMut {
162 size: self.size,
163 real_width: self.size.width() as usize,
164 data: &mut self.data,
165 }
166 }
167
168 pub(crate) fn subpixmap(&mut self, rect: IntRect) -> Option<SubPixmapMut<'_>> {
169 let rect = self.size.to_int_rect(0, 0).intersect(&rect)?;
170 let row_bytes = self.width() as usize;
171 let offset = rect.top() as usize * row_bytes + rect.left() as usize;
172
173 Some(SubPixmapMut {
174 size: rect.size(),
175 real_width: self.size.width() as usize,
176 data: &mut self.data[offset..],
177 })
178 }
179
180 #[cfg(feature = "png-format")]
184 pub fn decode_png(data: &[u8]) -> Result<Self, png::DecodingError> {
185 fn make_custom_png_error(msg: &str) -> png::DecodingError {
186 std::io::Error::new(std::io::ErrorKind::Other, msg).into()
187 }
188
189 let mut decoder = png::Decoder::new(std::io::BufReader::new(std::io::Cursor::new(data)));
190 decoder.set_transformations(png::Transformations::normalize_to_color8());
191 let mut reader = decoder.read_info()?;
192 let output_buffer_size = reader
193 .output_buffer_size()
194 .ok_or(png::DecodingError::LimitsExceeded)?;
195 let mut img_data = vec![0; output_buffer_size];
196 let info = reader.next_frame(&mut img_data)?;
197
198 if info.bit_depth != png::BitDepth::Eight {
199 return Err(make_custom_png_error("unsupported bit depth"));
200 }
201
202 if info.color_type != png::ColorType::Grayscale {
203 return Err(make_custom_png_error("only grayscale masks are supported"));
204 }
205
206 let size = IntSize::from_wh(info.width, info.height)
207 .ok_or_else(|| make_custom_png_error("invalid image size"))?;
208
209 Mask::from_vec(img_data, size)
210 .ok_or_else(|| make_custom_png_error("failed to create a mask"))
211 }
212
213 #[cfg(feature = "png-format")]
217 pub fn load_png<P: AsRef<std::path::Path>>(path: P) -> Result<Self, png::DecodingError> {
218 let data = std::fs::read(path)?;
222 Self::decode_png(&data)
223 }
224
225 #[cfg(feature = "png-format")]
227 pub fn encode_png(&self) -> Result<Vec<u8>, png::EncodingError> {
228 let mut data = Vec::new();
229 {
230 let mut encoder = png::Encoder::new(&mut data, self.width(), self.height());
231 encoder.set_color(png::ColorType::Grayscale);
232 encoder.set_depth(png::BitDepth::Eight);
233 let mut writer = encoder.write_header()?;
234 writer.write_image_data(&self.data)?;
235 }
236
237 Ok(data)
238 }
239
240 #[cfg(feature = "png-format")]
242 pub fn save_png<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), png::EncodingError> {
243 let data = self.encode_png()?;
244 std::fs::write(path, data)?;
245 Ok(())
246 }
247
248 pub fn fill_path(
260 &mut self,
261 path: &Path,
262 fill_rule: FillRule,
263 anti_alias: bool,
264 transform: Transform,
265 ) {
266 if transform.is_identity() {
267 let path_bounds = path.bounds();
271 if path_bounds.width().is_nearly_zero() || path_bounds.height().is_nearly_zero() {
272 log::warn!("empty paths and horizontal/vertical lines cannot be filled");
273 return;
274 }
275
276 if crate::painter::is_too_big_for_math(path) {
277 log::warn!("path coordinates are too big");
278 return;
279 }
280
281 if let Some(tiler) = DrawTiler::new(self.width(), self.height()) {
284 let mut path = path.clone(); for tile in tiler {
287 let ts = Transform::from_translate(-(tile.x() as f32), -(tile.y() as f32));
288 path = match path.transform(ts) {
289 Some(v) => v,
290 None => {
291 log::warn!("path transformation failed");
292 return;
293 }
294 };
295
296 let clip_rect = tile.size().to_screen_int_rect(0, 0);
297 let mut subpix = match self.subpixmap(tile.to_int_rect()) {
298 Some(v) => v,
299 None => continue, };
301
302 let mut blitter = match RasterPipelineBlitter::new_mask(&mut subpix) {
303 Some(v) => v,
304 None => continue, };
306
307 if anti_alias {
311 scan::path_aa::fill_path(&path, fill_rule, &clip_rect, &mut blitter);
312 } else {
313 scan::path::fill_path(&path, fill_rule, &clip_rect, &mut blitter);
314 }
315
316 let ts = Transform::from_translate(tile.x() as f32, tile.y() as f32);
317 path = match path.transform(ts) {
318 Some(v) => v,
319 None => return, };
321 }
322 } else {
323 let clip_rect = self.size().to_screen_int_rect(0, 0);
324 let mut subpix = self.as_subpixmap();
325 let mut blitter = match RasterPipelineBlitter::new_mask(&mut subpix) {
326 Some(v) => v,
327 None => return, };
329
330 if anti_alias {
331 scan::path_aa::fill_path(path, fill_rule, &clip_rect, &mut blitter);
332 } else {
333 scan::path::fill_path(path, fill_rule, &clip_rect, &mut blitter);
334 }
335 }
336 } else {
337 let path = match path.clone().transform(transform) {
338 Some(v) => v,
339 None => {
340 log::warn!("path transformation failed");
341 return;
342 }
343 };
344
345 self.fill_path(&path, fill_rule, anti_alias, Transform::identity());
346 }
347 }
348
349 pub fn intersect_path(
353 &mut self,
354 path: &Path,
355 fill_rule: FillRule,
356 anti_alias: bool,
357 transform: Transform,
358 ) {
359 let mut submask = Mask::new(self.width(), self.height()).unwrap();
360 submask.fill_path(path, fill_rule, anti_alias, transform);
361
362 for (a, b) in self.data.iter_mut().zip(submask.data.iter()) {
363 *a = crate::color::premultiply_u8(*a, *b);
364 }
365 }
366
367 pub fn invert(&mut self) {
369 self.data.iter_mut().for_each(|a| *a = 255 - *a);
370 }
371
372 pub fn clear(&mut self) {
376 self.data.fill(0);
377 }
378}
379
380impl core::fmt::Debug for Mask {
381 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
382 f.debug_struct("Mask")
383 .field("data", &"...")
384 .field("width", &self.size.width())
385 .field("height", &self.size.height())
386 .finish()
387 }
388}
389
390#[derive(Clone, Copy)]
391pub struct SubMaskRef<'a> {
392 pub data: &'a [u8],
393 pub size: IntSize,
394 pub real_width: u32,
395}
396
397impl<'a> SubMaskRef<'a> {
398 pub(crate) fn mask_ctx(&self) -> crate::pipeline::MaskCtx<'a> {
399 crate::pipeline::MaskCtx {
400 data: self.data,
401 real_width: self.real_width,
402 }
403 }
404}