diff --git a/crates/resvg/src/filter/morphology.rs b/crates/resvg/src/filter/morphology.rs
index 09585ebd8..980593fa2 100644
--- a/crates/resvg/src/filter/morphology.rs
+++ b/crates/resvg/src/filter/morphology.rs
@@ -13,19 +13,15 @@ use usvg::filter::MorphologyOperator;
///
/// This method will allocate a copy of the `src` image as a back buffer.
pub fn apply(operator: MorphologyOperator, rx: f32, ry: f32, src: ImageRefMut) {
- // No point in making matrix larger than image.
- let columns = std::cmp::min(rx.ceil() as u32 * 2, src.width);
- let rows = std::cmp::min(ry.ceil() as u32 * 2, src.height);
- let target_x = (columns as f32 / 2.0).floor() as u32;
- let target_y = (rows as f32 / 2.0).floor() as u32;
-
- let width_max = src.width as i32 - 1;
- let height_max = src.height as i32 - 1;
+ let width_max = src.width - 1;
+ let height_max = src.height - 1;
+ let rx = (rx.round() as u32).min(width_max);
+ let ry = (ry.round() as u32).min(height_max);
let mut buf = vec![RGBA8::default(); src.data.len()];
let mut buf = ImageRefMut::new(src.width, src.height, &mut buf);
- let mut x = 0;
- let mut y = 0;
+ let mut x: u32 = 0;
+ let mut y: u32 = 0;
for _ in src.data.iter() {
let mut new_p = RGBA8::default();
if operator == MorphologyOperator::Erode {
@@ -35,26 +31,22 @@ pub fn apply(operator: MorphologyOperator, rx: f32, ry: f32, src: ImageRefMut) {
new_p.a = 255;
}
- for oy in 0..rows {
- for ox in 0..columns {
- let tx = x as i32 - target_x as i32 + ox as i32;
- let ty = y as i32 - target_y as i32 + oy as i32;
-
- if tx < 0 || tx > width_max || ty < 0 || ty > height_max {
- continue;
- }
+ let x_range = x.saturating_sub(rx)..=(x + rx).min(width_max);
+ let y_range = y.saturating_sub(ry)..=(y + ry).min(height_max);
- let p = src.pixel_at(tx as u32, ty as u32);
+ for ty in y_range {
+ for tx in x_range.clone() {
+ let p = src.pixel_at(tx, ty);
if operator == MorphologyOperator::Erode {
- new_p.r = std::cmp::min(p.r, new_p.r);
- new_p.g = std::cmp::min(p.g, new_p.g);
- new_p.b = std::cmp::min(p.b, new_p.b);
- new_p.a = std::cmp::min(p.a, new_p.a);
+ new_p.r = p.r.min(new_p.r);
+ new_p.g = p.g.min(new_p.g);
+ new_p.b = p.b.min(new_p.b);
+ new_p.a = p.a.min(new_p.a);
} else {
- new_p.r = std::cmp::max(p.r, new_p.r);
- new_p.g = std::cmp::max(p.g, new_p.g);
- new_p.b = std::cmp::max(p.b, new_p.b);
- new_p.a = std::cmp::max(p.a, new_p.a);
+ new_p.r = p.r.max(new_p.r);
+ new_p.g = p.g.max(new_p.g);
+ new_p.b = p.b.max(new_p.b);
+ new_p.a = p.a.max(new_p.a);
}
}
}
diff --git a/crates/resvg/tests/integration/render.rs b/crates/resvg/tests/integration/render.rs
index cb1e91fa5..79c9e3c79 100644
--- a/crates/resvg/tests/integration/render.rs
+++ b/crates/resvg/tests/integration/render.rs
@@ -209,10 +209,13 @@ use crate::render;
#[test] fn filters_feMerge_color_interpolation_filters_eq_linearRGB() { assert_eq!(render("tests/filters/feMerge/color-interpolation-filters=linearRGB"), 0); }
#[test] fn filters_feMerge_color_interpolation_filters_eq_sRGB() { assert_eq!(render("tests/filters/feMerge/color-interpolation-filters=sRGB"), 0); }
#[test] fn filters_feMerge_complex_transform() { assert_eq!(render("tests/filters/feMerge/complex-transform"), 0); }
+#[test] fn filters_feMorphology_centered_kernel() { assert_eq!(render("tests/filters/feMorphology/centered-kernel"), 0); }
#[test] fn filters_feMorphology_empty_radius() { assert_eq!(render("tests/filters/feMorphology/empty-radius"), 0); }
+#[test] fn filters_feMorphology_fractional_radius() { assert_eq!(render("tests/filters/feMorphology/fractional-radius"), 0); }
#[test] fn filters_feMorphology_negative_radius() { assert_eq!(render("tests/filters/feMorphology/negative-radius"), 0); }
#[test] fn filters_feMorphology_no_radius() { assert_eq!(render("tests/filters/feMorphology/no-radius"), 0); }
#[test] fn filters_feMorphology_operator_eq_dilate() { assert_eq!(render("tests/filters/feMorphology/operator=dilate"), 0); }
+#[test] fn filters_feMorphology_radius_larger_than_region() { assert_eq!(render("tests/filters/feMorphology/radius-larger-than-region"), 0); }
#[test] fn filters_feMorphology_radius_with_too_many_values() { assert_eq!(render("tests/filters/feMorphology/radius-with-too-many-values"), 0); }
#[test] fn filters_feMorphology_radius_eq_0_5_with_objectBoundingBox() { assert_eq!(render("tests/filters/feMorphology/radius=0.5-with-objectBoundingBox"), 0); }
#[test] fn filters_feMorphology_radius_eq_0_5() { assert_eq!(render("tests/filters/feMorphology/radius=0.5"), 0); }
diff --git a/crates/resvg/tests/tests/filters/feMorphology/centered-kernel.png b/crates/resvg/tests/tests/filters/feMorphology/centered-kernel.png
new file mode 100644
index 000000000..52210b18e
Binary files /dev/null and b/crates/resvg/tests/tests/filters/feMorphology/centered-kernel.png differ
diff --git a/crates/resvg/tests/tests/filters/feMorphology/centered-kernel.svg b/crates/resvg/tests/tests/filters/feMorphology/centered-kernel.svg
new file mode 100644
index 000000000..d65f109b0
--- /dev/null
+++ b/crates/resvg/tests/tests/filters/feMorphology/centered-kernel.svg
@@ -0,0 +1,12 @@
+
diff --git a/crates/resvg/tests/tests/filters/feMorphology/empty-radius.png b/crates/resvg/tests/tests/filters/feMorphology/empty-radius.png
index 17dbf5945..f6638e93d 100644
Binary files a/crates/resvg/tests/tests/filters/feMorphology/empty-radius.png and b/crates/resvg/tests/tests/filters/feMorphology/empty-radius.png differ
diff --git a/crates/resvg/tests/tests/filters/feMorphology/fractional-radius.png b/crates/resvg/tests/tests/filters/feMorphology/fractional-radius.png
new file mode 100644
index 000000000..52210b18e
Binary files /dev/null and b/crates/resvg/tests/tests/filters/feMorphology/fractional-radius.png differ
diff --git a/crates/resvg/tests/tests/filters/feMorphology/fractional-radius.svg b/crates/resvg/tests/tests/filters/feMorphology/fractional-radius.svg
new file mode 100644
index 000000000..612f34410
--- /dev/null
+++ b/crates/resvg/tests/tests/filters/feMorphology/fractional-radius.svg
@@ -0,0 +1,12 @@
+
diff --git a/crates/resvg/tests/tests/filters/feMorphology/negative-radius.png b/crates/resvg/tests/tests/filters/feMorphology/negative-radius.png
index 17dbf5945..f6638e93d 100644
Binary files a/crates/resvg/tests/tests/filters/feMorphology/negative-radius.png and b/crates/resvg/tests/tests/filters/feMorphology/negative-radius.png differ
diff --git a/crates/resvg/tests/tests/filters/feMorphology/no-radius.png b/crates/resvg/tests/tests/filters/feMorphology/no-radius.png
index 17dbf5945..f6638e93d 100644
Binary files a/crates/resvg/tests/tests/filters/feMorphology/no-radius.png and b/crates/resvg/tests/tests/filters/feMorphology/no-radius.png differ
diff --git a/crates/resvg/tests/tests/filters/feMorphology/operator=dilate.png b/crates/resvg/tests/tests/filters/feMorphology/operator=dilate.png
index c67a4bb03..4c5a6f9a3 100644
Binary files a/crates/resvg/tests/tests/filters/feMorphology/operator=dilate.png and b/crates/resvg/tests/tests/filters/feMorphology/operator=dilate.png differ
diff --git a/crates/resvg/tests/tests/filters/feMorphology/radius-larger-than-region.png b/crates/resvg/tests/tests/filters/feMorphology/radius-larger-than-region.png
new file mode 100644
index 000000000..ca89852e2
Binary files /dev/null and b/crates/resvg/tests/tests/filters/feMorphology/radius-larger-than-region.png differ
diff --git a/crates/resvg/tests/tests/filters/feMorphology/radius-larger-than-region.svg b/crates/resvg/tests/tests/filters/feMorphology/radius-larger-than-region.svg
new file mode 100644
index 000000000..619b695a6
--- /dev/null
+++ b/crates/resvg/tests/tests/filters/feMorphology/radius-larger-than-region.svg
@@ -0,0 +1,12 @@
+
diff --git a/crates/resvg/tests/tests/filters/feMorphology/radius-with-too-many-values.png b/crates/resvg/tests/tests/filters/feMorphology/radius-with-too-many-values.png
index 17dbf5945..f6638e93d 100644
Binary files a/crates/resvg/tests/tests/filters/feMorphology/radius-with-too-many-values.png and b/crates/resvg/tests/tests/filters/feMorphology/radius-with-too-many-values.png differ
diff --git a/crates/resvg/tests/tests/filters/feMorphology/radius=0.5-with-objectBoundingBox.png b/crates/resvg/tests/tests/filters/feMorphology/radius=0.5-with-objectBoundingBox.png
index ec9b1a4d4..b629f4fbf 100644
Binary files a/crates/resvg/tests/tests/filters/feMorphology/radius=0.5-with-objectBoundingBox.png and b/crates/resvg/tests/tests/filters/feMorphology/radius=0.5-with-objectBoundingBox.png differ
diff --git a/crates/resvg/tests/tests/filters/feMorphology/radius=0.5.png b/crates/resvg/tests/tests/filters/feMorphology/radius=0.5.png
index 02ca2ab14..20877c5d1 100644
Binary files a/crates/resvg/tests/tests/filters/feMorphology/radius=0.5.png and b/crates/resvg/tests/tests/filters/feMorphology/radius=0.5.png differ
diff --git a/crates/resvg/tests/tests/filters/feMorphology/radius=1-10.png b/crates/resvg/tests/tests/filters/feMorphology/radius=1-10.png
index 4721f1252..c49c9b868 100644
Binary files a/crates/resvg/tests/tests/filters/feMorphology/radius=1-10.png and b/crates/resvg/tests/tests/filters/feMorphology/radius=1-10.png differ
diff --git a/crates/resvg/tests/tests/filters/feMorphology/radius=10-0.png b/crates/resvg/tests/tests/filters/feMorphology/radius=10-0.png
index 8e75958c9..3034ce86c 100644
Binary files a/crates/resvg/tests/tests/filters/feMorphology/radius=10-0.png and b/crates/resvg/tests/tests/filters/feMorphology/radius=10-0.png differ
diff --git a/crates/resvg/tests/tests/filters/feMorphology/radius=10-1.png b/crates/resvg/tests/tests/filters/feMorphology/radius=10-1.png
index 8e75958c9..3034ce86c 100644
Binary files a/crates/resvg/tests/tests/filters/feMorphology/radius=10-1.png and b/crates/resvg/tests/tests/filters/feMorphology/radius=10-1.png differ
diff --git a/crates/resvg/tests/tests/filters/feMorphology/simple-case.png b/crates/resvg/tests/tests/filters/feMorphology/simple-case.png
index 090f6d70b..0de4be989 100644
Binary files a/crates/resvg/tests/tests/filters/feMorphology/simple-case.png and b/crates/resvg/tests/tests/filters/feMorphology/simple-case.png differ
diff --git a/crates/resvg/tests/tests/filters/feMorphology/source-with-opacity.png b/crates/resvg/tests/tests/filters/feMorphology/source-with-opacity.png
index f9d807e53..1b0e335d4 100644
Binary files a/crates/resvg/tests/tests/filters/feMorphology/source-with-opacity.png and b/crates/resvg/tests/tests/filters/feMorphology/source-with-opacity.png differ
diff --git a/crates/resvg/tests/tests/filters/feMorphology/zero-radius.png b/crates/resvg/tests/tests/filters/feMorphology/zero-radius.png
index 17dbf5945..f6638e93d 100644
Binary files a/crates/resvg/tests/tests/filters/feMorphology/zero-radius.png and b/crates/resvg/tests/tests/filters/feMorphology/zero-radius.png differ