1use crate::{
29 Color, Curve, DEFAULT_FLATNESS, EPSILON, EPSILON_SQRT, FillRule, ImageMut, ImageOwned,
30 LinColor, Line, Path, Point, Scalar, Transform,
31};
32#[cfg(feature = "serde")]
33use serde::{Deserialize, Serialize};
34use std::{cmp::min, fmt, rc::Rc, sync::Arc};
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
38pub struct Size {
39 pub width: usize,
40 pub height: usize,
41}
42
43pub trait Rasterizer {
45 fn name(&self) -> &str;
47
48 fn mask(
51 &self,
52 path: &Path,
53 tr: Transform,
54 img: &mut dyn ImageMut<Pixel = Scalar>,
55 fill_rule: FillRule,
56 );
57
58 fn mask_iter(
62 &self,
63 path: &Path,
64 tr: Transform,
65 size: Size,
66 fill_rule: FillRule,
67 ) -> Box<dyn Iterator<Item = Pixel> + '_>;
68
69 fn fill(
71 &self,
72 path: &Path,
73 tr: Transform,
74 fill_rule: FillRule,
75 paint: &dyn Paint,
76 img: &mut dyn ImageMut<Pixel = LinColor>,
77 ) {
78 let pixels = self.mask_iter(path, tr, img.size(), fill_rule);
79 match paint.units() {
80 None => {
81 let color = paint.at(Point::new(0.0, 0.0));
82 fill_impl(pixels, img, |_| color);
83 }
84 Some(units) => {
85 let units_tr = match units {
86 Units::UserSpaceOnUse => tr * paint.transform(),
87 Units::BoundingBox => match path.bbox(Transform::identity()) {
88 None => return,
89 Some(bbox) => tr * bbox.unit_transform() * paint.transform(),
90 },
91 };
92 if let Some(pixel_tr) = units_tr.invert() {
93 fill_impl(pixels, img, |pixel| {
94 let point = Point::new(pixel.x as Scalar + 0.5, pixel.y as Scalar + 0.5);
95 paint.at(pixel_tr.apply(point))
96 })
97 }
98 }
99 }
100 }
101}
102
103fn fill_impl(
104 pixels: impl Iterator<Item = Pixel>,
105 mut img: impl ImageMut<Pixel = LinColor>,
106 color_at: impl Fn(Pixel) -> LinColor,
107) {
108 let shape = img.shape();
109 let data = img.data_mut();
110 for pixel in pixels {
111 let dst = &mut data[shape.offset(pixel.y, pixel.x)];
112 let color = color_at(pixel);
113 *dst = dst.blend_over(color.with_alpha(pixel.alpha));
114 }
115}
116
117impl<R: Rasterizer + ?Sized> Rasterizer for &R {
118 fn mask(
119 &self,
120 path: &Path,
121 tr: Transform,
122 img: &mut dyn ImageMut<Pixel = Scalar>,
123 fill_rule: FillRule,
124 ) {
125 (**self).mask(path, tr, img, fill_rule)
126 }
127
128 fn mask_iter(
129 &self,
130 path: &Path,
131 tr: Transform,
132 size: Size,
133 fill_rule: FillRule,
134 ) -> Box<dyn Iterator<Item = Pixel> + '_> {
135 (**self).mask_iter(path, tr, size, fill_rule)
136 }
137
138 fn name(&self) -> &str {
139 (**self).name()
140 }
141}
142
143impl Rasterizer for Box<dyn Rasterizer> {
144 fn mask(
145 &self,
146 path: &Path,
147 tr: Transform,
148 img: &mut dyn ImageMut<Pixel = Scalar>,
149 fill_rule: FillRule,
150 ) {
151 (**self).mask(path, tr, img, fill_rule)
152 }
153
154 fn mask_iter(
155 &self,
156 path: &Path,
157 tr: Transform,
158 size: Size,
159 fill_rule: FillRule,
160 ) -> Box<dyn Iterator<Item = Pixel> + '_> {
161 (**self).mask_iter(path, tr, size, fill_rule)
162 }
163
164 fn name(&self) -> &str {
165 (**self).name()
166 }
167}
168
169#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
170#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
171pub enum Units {
172 #[cfg_attr(feature = "serde", serde(rename = "userSpaceOnUse"))]
173 #[default]
174 UserSpaceOnUse,
175 #[cfg_attr(feature = "serde", serde(rename = "objectBoundingBox"))]
176 BoundingBox,
177}
178
179pub trait Paint: fmt::Debug {
181 fn at(&self, point: Point) -> LinColor;
183
184 fn units(&self) -> Option<Units>;
186
187 fn transform(&self) -> Transform;
189
190 #[cfg(feature = "serde")]
192 fn to_json(&self) -> Result<serde_json::Value, crate::SvgParserError>;
193}
194
195impl<P: Paint> Paint for &P {
196 fn at(&self, point: Point) -> LinColor {
197 (**self).at(point)
198 }
199
200 fn units(&self) -> Option<Units> {
201 (**self).units()
202 }
203
204 fn transform(&self) -> Transform {
205 (**self).transform()
206 }
207
208 #[cfg(feature = "serde")]
209 fn to_json(&self) -> Result<serde_json::Value, crate::SvgParserError> {
210 (**self).to_json()
211 }
212}
213
214impl Paint for Box<dyn Paint> {
215 fn at(&self, point: Point) -> LinColor {
216 (**self).at(point)
217 }
218
219 fn units(&self) -> Option<Units> {
220 (**self).units()
221 }
222
223 fn transform(&self) -> Transform {
224 (**self).transform()
225 }
226
227 #[cfg(feature = "serde")]
228 fn to_json(&self) -> Result<serde_json::Value, crate::SvgParserError> {
229 (**self).to_json()
230 }
231}
232
233impl Paint for Rc<dyn Paint> {
234 fn at(&self, point: Point) -> LinColor {
235 (**self).at(point)
236 }
237
238 fn units(&self) -> Option<Units> {
239 (**self).units()
240 }
241
242 fn transform(&self) -> Transform {
243 (**self).transform()
244 }
245
246 #[cfg(feature = "serde")]
247 fn to_json(&self) -> Result<serde_json::Value, crate::SvgParserError> {
248 (**self).to_json()
249 }
250}
251
252impl Paint for Arc<dyn Paint> {
253 fn at(&self, point: Point) -> LinColor {
254 (**self).at(point)
255 }
256
257 fn units(&self) -> Option<Units> {
258 (**self).units()
259 }
260
261 fn transform(&self) -> Transform {
262 (**self).transform()
263 }
264
265 #[cfg(feature = "serde")]
266 fn to_json(&self) -> Result<serde_json::Value, crate::SvgParserError> {
267 (**self).to_json()
268 }
269}
270
271pub type ArcPaint = Arc<dyn Paint + Send + Sync + 'static>;
272
273#[derive(Debug, Clone)]
275pub struct SignedDifferenceRasterizer {
276 flatness: Scalar,
277}
278
279impl SignedDifferenceRasterizer {
280 pub fn new(flatness: Scalar) -> Self {
281 Self { flatness }
282 }
283}
284
285impl Default for SignedDifferenceRasterizer {
286 fn default() -> Self {
287 Self {
288 flatness: DEFAULT_FLATNESS,
289 }
290 }
291}
292
293impl Rasterizer for SignedDifferenceRasterizer {
294 fn mask(
295 &self,
296 path: &Path,
297 tr: Transform,
298 img: &mut dyn ImageMut<Pixel = Scalar>,
299 fill_rule: FillRule,
300 ) {
301 let mut img = img.as_mut();
302 for line in path.flatten(tr, self.flatness, true) {
303 signed_difference_line(&mut img, line);
304 }
305 signed_difference_to_mask(img, fill_rule);
306 }
307
308 fn mask_iter(
309 &self,
310 path: &Path,
311 tr: Transform,
312 size: Size,
313 fill_rule: FillRule,
314 ) -> Box<dyn Iterator<Item = Pixel> + '_> {
315 if size.width == 0 || size.height == 0 {
316 return Box::new(std::iter::empty());
317 }
318 let width = size.width;
319 let size = Size {
321 width: width + 1,
322 height: size.height,
323 };
324 let mut img = ImageOwned::new_default(size);
325 for line in path.flatten(tr, self.flatness, true) {
326 signed_difference_line(&mut img, line);
327 }
328 let mut winding = 0.0;
329 let iter =
330 img.into_vec()
331 .into_iter()
332 .enumerate()
333 .filter_map(move |(index, winding_diff)| {
334 let y = index / size.width;
335 let x = index - y * size.width;
336 if x == 0 {
337 winding = 0.0;
338 } else if x >= width {
339 return None;
340 }
341 winding += winding_diff;
342 let alpha = fill_rule.alpha_from_winding(winding);
343 if alpha.abs() < 1e-6 {
344 None
345 } else {
346 Some(Pixel { x, y, alpha })
347 }
348 });
349 Box::new(iter)
350 }
351
352 fn name(&self) -> &str {
353 "signed-difference"
354 }
355}
356
357fn signed_difference_line(mut img: impl ImageMut<Pixel = Scalar>, line: Line) {
361 let Line([p0, p1]) = line;
364
365 let width = img.width() as Scalar - 1.0;
368 let line = if p0.x() > width || p1.x() > width {
369 if p0.x() > width && p1.x() > width {
370 Line::new((width - 0.001, p0.y()), (width - 0.001, p1.y()))
371 } else {
372 let t = (p0.x() - width) / (p0.x() - p1.x());
373 let mid = Point::new(width, (1.0 - t) * p0.y() + t * p1.y());
374 if p0.x() < width {
375 Line::new(p0, mid)
376 } else {
377 Line::new(mid, p1)
378 }
379 }
380 } else {
381 line
382 };
383
384 let (line, rest) = split_at_zero_x(line);
386 if let Some(rest) = rest {
387 signed_difference_line(img.as_mut(), rest);
388 }
389
390 let Line([p0, p1]) = line;
391 let shape = img.shape();
392 let data = img.data_mut();
393 let stride = shape.col_stride;
394
395 if (p0.y() - p1.y()).abs() < EPSILON {
396 return;
398 }
399 let (dir, p0, p1) = if p0.y() < p1.y() {
401 (1.0, p0, p1)
402 } else {
403 (-1.0, p1, p0)
404 };
405 let dxdy = (p1.x() - p0.x()) / (p1.y() - p0.y());
406 let y = p0.y().max(0.0) as usize;
410 let mut x = if p0.y() < 0.0 {
411 p0.x() - p0.y() * dxdy
412 } else {
413 p0.x()
414 };
415 let mut x_next = x;
416 for y in y..min(shape.height, p1.y().ceil().max(0.0) as usize) {
417 x = x_next;
418 let row_offset = shape.offset(y, 0); let dy = ((y + 1) as Scalar).min(p1.y()) - (y as Scalar).max(p0.y());
420 let d = dir * dy;
422 x_next = x + dxdy * dy;
424 let (x0, x1) = if x < x_next { (x, x_next) } else { (x_next, x) };
426 let x0_floor = x0.floor().max(0.0);
428 let x0i = x0_floor as i32;
429 let x1_ceil = x1.ceil().min(width);
431 let x1i = x1_ceil as i32;
432 if x1i <= x0i + 1 {
433 let xmf = 0.5 * (x + x_next) - x0_floor; data[row_offset + (x0i as usize) * stride] += d * (1.0 - xmf);
436 let offset = row_offset + ((x0i + 1) as usize) * stride;
437 if crate::utils::likely(offset < data.len()) {
438 data[offset] += d * xmf;
439 }
440 } else {
441 let s = (x1 - x0).recip();
442 let x0f = x0 - x0_floor; let x1f = x1 - x1_ceil + 1.0; let a0 = 0.5 * s * (1.0 - x0f) * (1.0 - x0f); let am = 0.5 * s * x1f * x1f; data[row_offset + (x0i as usize) * stride] += d * a0;
447 if x1i == x0i + 2 {
448 data[row_offset + ((x0i + 1) as usize) * stride] += d * (1.0 - a0 - am);
450 } else {
451 let a1 = s * (1.5 - x0f);
453 data[row_offset + ((x0i + 1) as usize) * stride] += d * (a1 - a0);
454 for xi in x0i + 2..x1i - 1 {
456 data[row_offset + (xi as usize) * stride] += d * s;
457 }
458 let a2 = a1 + (x1i - x0i - 3) as Scalar * s;
460 data[row_offset + ((x1i - 1) as usize) * stride] += d * (1.0 - a2 - am);
461 }
462 data[row_offset + (x1i as usize) * stride] += d * am
463 }
464 }
465}
466
467fn signed_difference_to_mask(mut img: impl ImageMut<Pixel = Scalar>, fill_rule: FillRule) {
469 let shape = img.shape();
470 let data = img.data_mut();
471 match fill_rule {
472 FillRule::NonZero => {
473 for y in 0..shape.height {
474 let mut acc = 0.0;
475 for x in 0..shape.width {
476 let offset = shape.offset(y, x);
477 acc += data[offset];
478
479 let value = acc.abs();
480 data[offset] = if value > 1.0 {
481 1.0
482 } else if value < 1e-6 {
483 0.0
484 } else {
485 value
486 };
487 }
488 }
489 }
490 FillRule::EvenOdd => {
491 for y in 0..shape.height {
492 let mut acc = 0.0;
493 for x in 0..shape.width {
494 let offset = shape.offset(y, x);
495 acc += data[offset];
496
497 data[offset] = ((acc + 1.0).rem_euclid(2.0) - 1.0).abs()
498 }
499 }
500 }
501 }
502}
503
504#[derive(Debug, Clone)]
513pub struct ActiveEdgeRasterizer {
514 flatness: Scalar,
515}
516
517impl ActiveEdgeRasterizer {
518 pub fn new(flatness: Scalar) -> Self {
519 Self { flatness }
520 }
521}
522
523impl Default for ActiveEdgeRasterizer {
524 fn default() -> Self {
525 Self {
526 flatness: DEFAULT_FLATNESS,
527 }
528 }
529}
530
531impl Rasterizer for ActiveEdgeRasterizer {
532 fn mask(
533 &self,
534 path: &Path,
535 tr: Transform,
536 img: &mut dyn ImageMut<Pixel = Scalar>,
537 fill_rule: FillRule,
538 ) {
539 let shape = img.shape();
540 let data = img.data_mut();
541 for pixel in ActiveEdgeIter::new(
542 Size {
543 width: shape.width,
544 height: shape.height,
545 },
546 fill_rule,
547 path.flatten(tr, self.flatness, true),
548 ) {
549 data[shape.offset(pixel.y, pixel.x)] = pixel.alpha;
550 }
551 }
552
553 fn mask_iter(
554 &self,
555 path: &Path,
556 tr: Transform,
557 size: Size,
558 fill_rule: FillRule,
559 ) -> Box<dyn Iterator<Item = Pixel> + '_> {
560 Box::new(ActiveEdgeIter::new(
561 size,
562 fill_rule,
563 path.flatten(tr, self.flatness, true),
564 ))
565 }
566
567 fn name(&self) -> &str {
568 "active-edge"
569 }
570}
571
572pub struct ActiveEdgeIter {
574 edge_inactive: Vec<Edge>,
576 edge_active: Vec<Edge>,
578 iters_inactive: Vec<EdgeRowIter>,
580 iters_active: EdgeAccIter,
582 winding: Scalar,
584 fill_rule: FillRule,
586 size: Size,
588 column: usize,
590 row: usize,
592}
593
594impl ActiveEdgeIter {
595 pub fn new(size: Size, fill_rule: FillRule, lines: impl Iterator<Item = Line>) -> Self {
596 let mut edge_inactive: Vec<Edge> = lines
597 .flat_map(|line| {
598 let (line, rest) = split_at_zero_x(line);
599 std::iter::once(line).chain(rest)
600 })
601 .filter_map(|line| {
602 let edge = Edge::new(line)?;
603 (edge.row < size.height).then_some(edge)
604 })
605 .collect();
606 edge_inactive.sort_unstable_by(|l, r| l.row.cmp(&r.row).reverse());
607 let mut this = Self {
608 edge_inactive,
609 edge_active: Default::default(),
610 iters_inactive: Default::default(),
611 iters_active: EdgeAccIter::new(),
612 winding: 0.0,
613 fill_rule,
614 size,
615 column: 0,
616 row: 0,
617 };
618 this.next_row();
619 this
620 }
621
622 fn next_row(&mut self) {
624 self.iters_inactive.clear();
626 self.iters_active.clear();
627
628 self.edge_active.retain_mut(|edge| {
630 if let Some((edge_rest, iter)) = edge.next_row() {
632 self.iters_inactive.push(iter);
633 *edge = edge_rest;
634 true
635 } else {
636 false
637 }
638 });
639
640 let activate_index = self
642 .edge_inactive
643 .partition_point(|edge| edge.row > self.row);
644 self.edge_inactive
645 .drain(activate_index..)
646 .filter_map(|edge| edge.next_row())
647 .for_each(|(edge, iter)| {
648 self.iters_inactive.push(iter);
649 self.edge_active.push(edge);
650 });
651
652 self.iters_inactive
654 .sort_unstable_by(|a, b| b.column.cmp(&a.column));
655 }
656}
657
658#[derive(Debug, Clone, Copy)]
660pub struct Pixel {
661 pub x: usize,
663 pub y: usize,
665 pub alpha: Scalar,
667}
668
669impl Iterator for ActiveEdgeIter {
670 type Item = Pixel;
671
672 fn next(&mut self) -> Option<Self::Item> {
673 loop {
674 if self.row >= self.size.height {
675 return None;
676 }
677
678 while let Some(iter) = self.iters_inactive.pop() {
680 if iter.column <= self.column {
681 self.iters_active.push(iter);
682 } else {
683 self.iters_inactive.push(iter);
684 break;
685 }
686 }
687
688 match self.iters_active.next() {
690 Some(winding_delta) => self.winding += winding_delta,
691 None if self.winding.abs() < EPSILON_SQRT => {
692 match self.iters_inactive.last() {
694 Some(iter) if iter.column < self.size.width => {
695 self.column = iter.column;
696 }
697 _ => {
698 self.column = 0;
699 self.row += 1;
700 self.winding = 0.0;
701 self.next_row();
702 }
703 }
704 continue;
705 }
706 None => {}
707 }
708
709 let pixel = Pixel {
710 x: self.column,
711 y: self.row,
712 alpha: self.fill_rule.alpha_from_winding(self.winding),
713 };
714
715 self.column += 1;
717 if self.column >= self.size.width {
718 self.column = 0;
719 self.row += 1;
720 self.winding = 0.0;
721 self.next_row();
722 }
723
724 return Some(pixel);
725 }
726 }
727}
728
729#[inline]
730fn next_ceil(value: Scalar) -> Scalar {
731 value.floor() + 1.0
732}
733
734#[derive(Debug, Clone, Copy)]
738struct Edge {
739 line: Line,
741 dxdy: Scalar,
743 dydx: Option<Scalar>,
745 dir: Scalar,
747 row: usize,
749}
750
751impl Edge {
752 fn new(line: Line) -> Option<Self> {
756 let Line([p0, p1]) = line;
757 if (p0.y() - p1.y()).abs() < EPSILON {
758 return None;
760 }
761 let (dir, p0, p1) = if p0.y() <= p1.y() {
763 (1.0, p0, p1)
764 } else {
765 (-1.0, p1, p0)
766 };
767 let dx = p1.x() - p0.x();
768 let dy = p1.y() - p0.y();
769 let dxdy = dx / dy;
770 #[allow(clippy::unnecessary_lazy_evaluations)]
772 let dydx = (dxdy.abs() > EPSILON_SQRT).then(|| dy / dx);
773 let p0 = if p0.y() < 0.0 {
775 Point::new(p0.x() - p0.y() * dxdy, 0.0)
776 } else {
777 p0
778 };
779 Some(Self {
780 line: Line::new(p0, p1),
781 dxdy,
782 dydx,
783 dir,
784 row: p0.y().floor() as usize,
785 })
786 }
787
788 fn next_row(&self) -> Option<(Edge, EdgeRowIter)> {
791 EdgeRowIter::new(*self)
792 }
793}
794
795#[derive(Debug)]
801struct EdgeRowIter {
802 line: Option<Line>,
804 reminder: Option<Scalar>,
806 dydx: Option<Scalar>,
808 column: usize,
810 dir: Scalar,
812}
813
814impl EdgeRowIter {
815 fn new(mut edge: Edge) -> Option<(Edge, Self)> {
816 let Line([p0, p1]) = edge.line;
817 if p1.y() - p0.y() < EPSILON {
818 return None;
820 }
821
822 let y_split = next_ceil(p0.y()).min(p1.y());
824 let x_split = p0.x() + edge.dxdy * (y_split - p0.y());
825 let p_split = Point::new(x_split, y_split);
826
827 edge.line = Line::new(p_split, p1);
829
830 let (dir, line) = if p0.x() <= p_split.x() {
832 (edge.dir, Line::new(p0, p_split))
833 } else {
834 (-edge.dir, Line::new(p_split, p0))
835 };
836
837 let iter = Self {
838 line: Some(line),
839 reminder: None,
840 dydx: edge.dydx,
841 column: line.start().x() as usize,
842 dir,
843 };
844 Some((edge, iter))
845 }
846}
847
848impl Iterator for EdgeRowIter {
849 type Item = Scalar;
850
851 fn next(&mut self) -> Option<Self::Item> {
852 if let Some(Line([p0, p1])) = self.line.take() {
853 let x_ceil = next_ceil(p0.x());
854 let x = x_ceil.min(p1.x());
855 let h = match self.dydx {
856 Some(dydx) => dydx * (x - p0.x()),
857 None => next_ceil(p0.y()).min(p1.y()) - p0.y(),
858 };
859 let y = p0.y() + h;
860 let s0 = (2.0 * x_ceil - x - p0.x()) * h / 2.0;
861 let s1 = h - s0;
862 if p1.x() > x {
863 self.line = Some(Line::new((x, y), p1));
864 }
865 let s_prev = self.reminder.replace(self.dir * s1).unwrap_or(0.0);
866 Some(self.dir * s0 + s_prev)
867 } else {
868 self.reminder.take()
869 }
870 }
871}
872
873struct EdgeAccIter {
877 iters: Vec<EdgeRowIter>,
878}
879
880impl EdgeAccIter {
881 fn new() -> Self {
882 Self {
883 iters: Default::default(),
884 }
885 }
886
887 fn push(&mut self, iter: EdgeRowIter) {
889 self.iters.push(iter)
890 }
891
892 fn clear(&mut self) {
894 self.iters.clear()
895 }
896}
897
898impl Iterator for EdgeAccIter {
899 type Item = Scalar;
900
901 fn next(&mut self) -> Option<Self::Item> {
902 if self.iters.is_empty() {
903 return None;
904 }
905 let mut acc = 0.0;
906 self.iters.retain_mut(|iter| match iter.next() {
907 Some(value) => {
908 acc += value;
909 true
910 }
911 None => false,
912 });
913 Some(acc)
914 }
915}
916
917fn split_at_zero_x(line: Line) -> (Line, Option<Line>) {
919 let Line([p0, p1]) = line;
920 if p0.x() >= 0.0 && p1.x() >= 0.0 {
921 return (line, None);
922 }
923 if p0.x() <= 0.0 && p1.x() <= 0.0 {
924 return (Line::new((0.0, p0.y()), (0.0, p1.y())), None);
925 }
926 let mid = line.at(p0.x() / (p0.x() - p1.x()));
927 if p0.x() < 0.0 {
928 (Line::new(mid, p1), Some(Line::new((0.0, p0.y()), mid)))
929 } else {
930 (Line::new(p0, mid), Some(Line::new(mid, (0.0, p1.y()))))
931 }
932}
933
934#[cfg(test)]
935mod tests {
936 use super::*;
937 use crate::{Image, assert_approx_eq};
938 type Error = Box<dyn std::error::Error>;
939
940 #[test]
941 fn test_signed_difference_line() {
942 let mut img = ImageOwned::new_default(Size {
943 height: 2,
944 width: 5,
945 });
946
947 signed_difference_line(&mut img, Line::new((0.5, 1.0), (3.5, 0.0)));
949 let a0 = (0.5 * (1.0 / 6.0)) / 2.0;
951 let a1 = ((1.0 / 6.0) + (3.0 / 6.0)) / 2.0;
952 let a2 = ((3.0 / 6.0) + (5.0 / 6.0)) / 2.0;
953 assert_approx_eq!(*img.get(0, 0).unwrap(), -a0);
954 assert_approx_eq!(*img.get(0, 1).unwrap(), a0 - a1);
955 assert_approx_eq!(*img.get(0, 2).unwrap(), a1 - a2);
956 assert_approx_eq!(*img.get(0, 3).unwrap(), a0 - a1);
957 assert_approx_eq!(*img.get(0, 4).unwrap(), -a0);
958 let a: Scalar = img.iter().sum();
960 assert_approx_eq!(a, -1.0);
961 img.clear();
962
963 signed_difference_line(&mut img, Line::new((-1.0, 0.0), (1.0, 1.0)));
965 assert_approx_eq!(*img.get(0, 0).unwrap(), 3.0 / 4.0);
966 assert_approx_eq!(*img.get(0, 1).unwrap(), 1.0 / 4.0);
967 img.clear();
968
969 signed_difference_line(&mut img, Line::new((0.0, -0.5), (2.0, 1.5)));
971 assert_approx_eq!(*img.get(0, 0).unwrap(), 1.0 / 8.0);
972 assert_approx_eq!(*img.get(0, 1).unwrap(), 1.0 - 2.0 / 8.0);
973 assert_approx_eq!(*img.get(0, 2).unwrap(), 1.0 / 8.0);
974 assert_approx_eq!(*img.get(1, 1).unwrap(), 1.0 / 8.0);
975 assert_approx_eq!(*img.get(1, 2).unwrap(), 0.5 - 1.0 / 8.0);
976 img.clear();
977
978 signed_difference_line(&mut img, Line::new((0.1, 0.1), (1.9, 0.9)));
980 assert_approx_eq!(*img.get(0, 0).unwrap(), 0.18);
981 assert_approx_eq!(*img.get(0, 1).unwrap(), 0.44);
982 assert_approx_eq!(*img.get(0, 2).unwrap(), 0.18);
983 img.clear();
984
985 signed_difference_line(&mut img, Line::new((0.1, 0.1), (0.9, 0.9)));
987 assert_approx_eq!(*img.get(0, 0).unwrap(), 0.4);
988 assert_approx_eq!(*img.get(0, 1).unwrap(), 0.8 - 0.4);
989 img.clear();
990
991 signed_difference_line(&mut img, Line::new((0.5, 0.5), (0.5, 1.75)));
993 assert_approx_eq!(*img.get(0, 0).unwrap(), 1.0 / 4.0);
994 assert_approx_eq!(*img.get(0, 1).unwrap(), 1.0 / 4.0);
995 assert_approx_eq!(*img.get(1, 0).unwrap(), 3.0 / 8.0);
996 assert_approx_eq!(*img.get(1, 1).unwrap(), 3.0 / 8.0);
997 img.clear();
998 }
999
1000 #[test]
1001 fn test_edge_iter() {
1002 let line = Line::new((0.0, 0.0), (6.0, 2.0));
1003 let edge = Edge::new(line).unwrap();
1004 assert_eq!(edge.row, 0);
1005 let (edge, mut iter) = edge.next_row().unwrap();
1007 assert_eq!(iter.column, 0);
1008 assert_approx_eq!(iter.next().unwrap(), 1.0 / 6.0);
1009 assert_approx_eq!(iter.next().unwrap(), 2.0 / 6.0);
1010 assert_approx_eq!(iter.next().unwrap(), 2.0 / 6.0);
1011 assert_approx_eq!(iter.next().unwrap(), 1.0 / 6.0);
1012 assert!(iter.next().is_none());
1013 let (edge, iter) = edge.next_row().unwrap();
1015 assert_eq!(iter.column, 3);
1016 assert_approx_eq!(iter.sum::<Scalar>(), 1.0);
1017 assert!(edge.next_row().is_none());
1019
1020 let line = Line::new((1.0, 1.0), (4.0, 0.0));
1021 let edge = Edge::new(line).unwrap();
1022 assert_eq!(edge.row, 0);
1023 let (edge, mut iter) = edge.next_row().unwrap();
1025 assert_eq!(iter.column, 1);
1026 assert_approx_eq!(iter.next().unwrap(), -1.0 / 6.0);
1027 assert_approx_eq!(iter.next().unwrap(), -2.0 / 6.0);
1028 assert_approx_eq!(iter.next().unwrap(), -2.0 / 6.0);
1029 assert_approx_eq!(iter.next().unwrap(), -1.0 / 6.0);
1030 assert!(edge.next_row().is_none());
1032
1033 let line = Line::new((0.5, 0.5), (0.5, 1.5));
1035 let edge = Edge::new(line).unwrap();
1036 assert_eq!(edge.row, 0);
1037 let (edge, mut iter) = edge.next_row().unwrap();
1039 assert_eq!(iter.column, 0);
1040 assert_approx_eq!(iter.next().unwrap(), 1.0 / 4.0);
1041 assert_approx_eq!(iter.next().unwrap(), 1.0 / 4.0);
1042 assert!(iter.next().is_none());
1043 let (edge, iter) = edge.next_row().unwrap();
1045 assert_approx_eq!(iter.sum::<Scalar>(), 0.5);
1046 assert!(edge.next_row().is_none());
1048
1049 let line = Line::new((0.5, 0.2), (0.5 + EPSILON_SQRT, 0.7));
1050 let edge = Edge::new(line).unwrap();
1051 assert_eq!(edge.row, 0);
1052 let (edge, mut iter) = edge.next_row().unwrap();
1053 assert_eq!(iter.column, 0);
1054 assert_approx_eq!(iter.next().unwrap(), 1.0 / 4.0, 1e-6);
1055 assert_approx_eq!(iter.next().unwrap(), 1.0 / 4.0, 1e-6);
1056 assert!(iter.next().is_none());
1057 assert!(edge.next_row().is_none());
1058 }
1059
1060 fn test_rasterizer(rasterizer: &dyn Rasterizer) -> Result<(), Error> {
1061 #[rustfmt::skip]
1062 let expected = [
1063 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 0.5, 0.0, 0.0, 0.0, 0.25, 0.75, 1.0, 0.75, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ];
1069
1070 let path = Path::builder()
1071 .move_to((1.0, 0.0))
1072 .line_to((1.0, 1.0))
1073 .line_to((2.0, 2.0))
1074 .line_to((4.0, 3.0))
1075 .line_to((5.0, 3.0))
1076 .line_to((7.0, 2.0))
1077 .line_to((8.0, 1.0))
1078 .line_to((8.0, 0.0))
1079 .close()
1080 .build();
1081
1082 let mut img = ImageOwned::new_default(Size {
1083 width: 9,
1084 height: 4,
1085 });
1086 rasterizer.mask(&path, Transform::identity(), &mut img, FillRule::EvenOdd);
1087 for (expected, pixel) in expected.iter().zip(img.data()) {
1088 assert_approx_eq!(expected, pixel);
1089 }
1090
1091 let path: Path = "M1,1 v2 h1 v-2 Z".parse()?;
1093 let mut img = ImageOwned::new_default(Size {
1094 width: 3,
1095 height: 3,
1096 });
1097 rasterizer.mask(&path, Transform::identity(), &mut img, FillRule::EvenOdd);
1098
1099 {
1100 let file = std::fs::File::create("/tmp/bla.bmp")?;
1101 img.write_bmp(file)?;
1102 }
1103
1104 Ok(())
1105 }
1106
1107 #[test]
1108 fn test_active_edge_rasterizer() -> Result<(), Error> {
1109 test_rasterizer(&ActiveEdgeRasterizer::default())
1110 }
1111
1112 #[test]
1113 fn test_sigend_difference_rasterizer() -> Result<(), Error> {
1114 test_rasterizer(&SignedDifferenceRasterizer::default())
1115 }
1116
1117 #[test]
1118 fn test_fill_rule() {
1119 let tr = Transform::identity();
1120 let path: Path = r#"
1121 M50,0 21,90 98,35 2,35 79,90z
1122 M110,0 h90 v90 h-90z
1123 M130,20 h50 v50 h-50 z
1124 M210,0 h90 v90 h-90 z
1125 M230,20 v50 h50 v-50 z
1126 "#
1127 .parse()
1128 .expect("failed to parse path");
1129 let (size, tr, _) = path.size(tr).expect("path is empty");
1130 let mut img = ImageOwned::new_default(size);
1131
1132 let y = 50;
1133 let x0 = 50; let x1 = 150; let x2 = 250; let r0: Box<dyn Rasterizer> = Box::new(SignedDifferenceRasterizer::default());
1138 let r1: Box<dyn Rasterizer> = Box::new(ActiveEdgeRasterizer::default());
1139 for rasterizer in &[r0, r1] {
1140 img.clear();
1141 path.mask(rasterizer, tr, FillRule::EvenOdd, &mut img);
1142 assert_approx_eq!(img.get(y, x0).unwrap(), 0.0, 1e-6);
1143 assert_approx_eq!(img.get(y, x1).unwrap(), 0.0, 1e-6);
1144 assert_approx_eq!(img.get(y, x2).unwrap(), 0.0, 1e-6);
1145 let area = img.iter().sum::<Scalar>();
1146 assert_approx_eq!(area, 13130.0, 1.0);
1147
1148 img.clear();
1149 path.mask(rasterizer, tr, FillRule::NonZero, &mut img);
1150 assert_approx_eq!(img.get(y, x0).unwrap(), 1.0, 1e-6);
1151 assert_approx_eq!(img.get(y, x1).unwrap(), 1.0, 1e-6);
1152 assert_approx_eq!(img.get(y, x2).unwrap(), 0.0, 1e-6);
1153 let area = img.iter().sum::<Scalar>();
1154 assert_approx_eq!(area, 16492.5, 1.0);
1155 }
1156 }
1157}