diff --git a/crates/resvg/src/filter/composite.rs b/crates/resvg/src/filter/composite.rs index d2deed0a0..4460678a6 100644 --- a/crates/resvg/src/filter/composite.rs +++ b/crates/resvg/src/filter/composite.rs @@ -1,7 +1,7 @@ // Copyright 2020 the Resvg Authors // SPDX-License-Identifier: Apache-2.0 OR MIT -use super::{ImageRef, ImageRefMut, f32_bound}; +use super::{Error, ImageRef, ImageRefMut, f32_bound}; use rgb::RGBA8; use usvg::ApproxZeroUlps; @@ -9,10 +9,6 @@ use usvg::ApproxZeroUlps; /// /// - `src1` and `src2` image pixels should have a **premultiplied alpha**. /// - `dest` image pixels will have a **premultiplied alpha**. -/// -/// # Panics -/// -/// When `src1`, `src2` and `dest` have different sizes. pub fn arithmetic( k1: f32, k2: f32, @@ -21,9 +17,13 @@ pub fn arithmetic( src1: ImageRef, src2: ImageRef, dest: ImageRefMut, -) { - assert!(src1.width == src2.width && src1.width == dest.width); - assert!(src1.height == src2.height && src1.height == dest.height); +) -> Result<(), Error> { + if src1.width != src2.width || src1.width != dest.width { + return Err(Error::InvalidRegion); + } + if src1.height != src2.height || src1.height != dest.height { + return Err(Error::InvalidRegion); + } let calc = |i1, i2, max| { let i1 = i1 as f32 / 255.0; @@ -49,4 +49,5 @@ pub fn arithmetic( i += 1; } + Ok(()) } diff --git a/crates/resvg/src/filter/convolve_matrix.rs b/crates/resvg/src/filter/convolve_matrix.rs index bd14dfe32..7cd354eeb 100644 --- a/crates/resvg/src/filter/convolve_matrix.rs +++ b/crates/resvg/src/filter/convolve_matrix.rs @@ -12,7 +12,7 @@ use usvg::filter::{ConvolveMatrix, EdgeMode}; /// # Allocations /// /// This method will allocate a copy of the `src` image as a back buffer. -pub fn apply(matrix: &ConvolveMatrix, src: ImageRefMut) { +pub fn apply(matrix: &ConvolveMatrix, src: ImageRefMut) -> Result<(), super::Error> { fn bound(min: i32, val: i32, max: i32) -> i32 { core::cmp::max(min, core::cmp::min(max, val)) } @@ -57,10 +57,13 @@ pub fn apply(matrix: &ConvolveMatrix, src: ImageRefMut) { } } - let k = matrix.matrix().get( - matrix.matrix().columns() - ox - 1, - matrix.matrix().rows() - oy - 1, - ); + let k = matrix + .matrix() + .get( + matrix.matrix().columns() - ox - 1, + matrix.matrix().rows() - oy - 1, + ) + .ok_or(super::Error::InvalidRegion)?; let p = src.pixel_at(tx as u32, ty as u32); new_r += (p.r as f32) / 255.0 * k; @@ -108,4 +111,6 @@ pub fn apply(matrix: &ConvolveMatrix, src: ImageRefMut) { // Do not use `mem::swap` because `data` referenced via FFI. src.data.copy_from_slice(buf.data); + + Ok(()) } diff --git a/crates/resvg/src/filter/displacement_map.rs b/crates/resvg/src/filter/displacement_map.rs index 8e0222173..0948fca22 100644 --- a/crates/resvg/src/filter/displacement_map.rs +++ b/crates/resvg/src/filter/displacement_map.rs @@ -10,10 +10,6 @@ use usvg::filter::{ColorChannel, DisplacementMap}; /// - `src` pixels can have any alpha method. /// /// `sx` and `sy` indicate canvas scale. -/// -/// # Panics -/// -/// When `src`, `map` and `dest` have different sizes. pub fn apply( fe: &DisplacementMap, sx: f32, @@ -21,9 +17,13 @@ pub fn apply( src: ImageRef, map: ImageRef, dest: ImageRefMut, -) { - assert!(src.width == map.width && src.width == dest.width); - assert!(src.height == map.height && src.height == dest.height); +) -> Result<(), super::Error> { + if src.width != map.width || src.width != dest.width { + return Err(super::Error::InvalidRegion); + } + if src.height != map.height || src.height != dest.height { + return Err(super::Error::InvalidRegion); + } let w = src.width as i32; let h = src.height as i32; @@ -61,4 +61,5 @@ pub fn apply( y += 1; } } + Ok(()) } diff --git a/crates/resvg/src/filter/lighting.rs b/crates/resvg/src/filter/lighting.rs index 36a644b0d..1c48c60ff 100644 --- a/crates/resvg/src/filter/lighting.rs +++ b/crates/resvg/src/filter/lighting.rs @@ -127,17 +127,15 @@ impl Normal { /// - `dest` will have an **unpremultiplied alpha**. /// /// Does nothing when `src` is less than 3x3. -/// -/// # Panics -/// -/// - When `src` and `dest` have different sizes. pub fn diffuse_lighting( fe: &DiffuseLighting, light_source: LightSource, src: ImageRef, dest: ImageRefMut, -) { - assert!(src.width == dest.width && src.height == dest.height); +) -> Result<(), crate::filter::Error> { + if src.width != dest.width || src.height != dest.height { + return Err(crate::filter::Error::InvalidRegion); + } let light_factor = |normal: Normal, light_vector: Vector3| { let k = if normal.normal.approx_zero() { @@ -164,6 +162,7 @@ pub fn diffuse_lighting( src, dest, ); + Ok(()) } /// Renders a specular lighting. @@ -172,17 +171,15 @@ pub fn diffuse_lighting( /// - `dest` will have a **premultiplied alpha**. /// /// Does nothing when `src` is less than 3x3. -/// -/// # Panics -/// -/// - When `src` and `dest` have different sizes. pub fn specular_lighting( fe: &SpecularLighting, light_source: LightSource, src: ImageRef, dest: ImageRefMut, -) { - assert!(src.width == dest.width && src.height == dest.height); +) -> Result<(), crate::filter::Error> { + if src.width != dest.width || src.height != dest.height { + return Err(crate::filter::Error::InvalidRegion); + } let light_factor = |normal: Normal, light_vector: Vector3| { let h = light_vector + Vector3::new(0.0, 0.0, 1.0); @@ -226,6 +223,7 @@ pub fn specular_lighting( src, dest, ); + Ok(()) } fn apply( diff --git a/crates/resvg/src/filter/mod.rs b/crates/resvg/src/filter/mod.rs index 36c56a5df..1652e6c2c 100644 --- a/crates/resvg/src/filter/mod.rs +++ b/crates/resvg/src/filter/mod.rs @@ -287,7 +287,9 @@ impl Image { self, color_space: usvg::filter::ColorInterpolation, ) -> Result { - if color_space != self.color_space { + if color_space == self.color_space { + Ok(self) + } else { let region = self.region; let mut image = self.take()?; @@ -302,8 +304,6 @@ impl Image { region, color_space, }) - } else { - Ok(self) } } @@ -348,7 +348,8 @@ pub fn apply( match result { Ok(_) => {} Err(Error::InvalidRegion) => { - log::warn!("Filter has an invalid region."); + let id = filter.id(); + log::warn!("Filter '{id}' has an invalid region."); } Err(Error::NoResults) => {} } @@ -747,7 +748,7 @@ fn apply_composite( pixmap1.as_image_ref(), pixmap2.as_image_ref(), pixmap.as_image_ref_mut(), - ); + )?; return Ok(Image::from_image(pixmap, cs)); } @@ -920,7 +921,7 @@ fn apply_convolve_matrix( demultiply_alpha(pixmap.data_mut().as_rgba_mut()); } - convolve_matrix::apply(fe, pixmap.as_image_ref_mut()); + convolve_matrix::apply(fe, pixmap.as_image_ref_mut())?; Ok(Image::from_image(pixmap, cs)) } @@ -973,7 +974,7 @@ fn apply_displacement_map( pixmap1.as_image_ref(), pixmap2.as_image_ref(), pixmap.as_image_ref_mut(), - ); + )?; Ok(Image::from_image(pixmap, cs)) } @@ -1026,7 +1027,7 @@ fn apply_diffuse_lighting( light_source, input.as_ref().as_image_ref(), pixmap.as_image_ref_mut(), - ); + )?; Ok(Image::from_image(pixmap, cs)) } @@ -1047,7 +1048,7 @@ fn apply_specular_lighting( light_source, input.as_ref().as_image_ref(), pixmap.as_image_ref_mut(), - ); + )?; Ok(Image::from_image(pixmap, cs)) } diff --git a/crates/resvg/src/lib.rs b/crates/resvg/src/lib.rs index 45a4d9d6c..9919ffca3 100644 --- a/crates/resvg/src/lib.rs +++ b/crates/resvg/src/lib.rs @@ -38,10 +38,10 @@ pub fn render( ) { let target_size = tiny_skia::IntSize::from_wh(pixmap.width(), pixmap.height()).unwrap(); let max_bbox = tiny_skia::IntRect::from_xywh( - -(target_size.width() as i32) * 2, - -(target_size.height() as i32) * 2, - target_size.width() * 5, - target_size.height() * 5, + -((target_size.width() as i32) * 2).max(1024), + -((target_size.height() as i32) * 2).max(1024), + (target_size.width() * 5).max(1024 * 2), + (target_size.height() * 5).max(1024 * 2), ) .unwrap(); diff --git a/crates/usvg/src/tree/filter.rs b/crates/usvg/src/tree/filter.rs index 896e118e0..f61288761 100644 --- a/crates/usvg/src/tree/filter.rs +++ b/crates/usvg/src/tree/filter.rs @@ -469,12 +469,8 @@ impl ConvolveMatrixData { } /// Returns a matrix value at the specified position. - /// - /// # Panics - /// - /// - When position is out of bounds. - pub fn get(&self, x: u32, y: u32) -> f32 { - self.data[(y * self.columns + x) as usize] + pub fn get(&self, x: u32, y: u32) -> Option { + self.data.get((y * self.columns + x) as usize).cloned() } }