diff --git a/crates/egui_extras/CHANGELOG.md b/crates/egui_extras/CHANGELOG.md index 311c37f4..2e9fd663 100644 --- a/crates/egui_extras/CHANGELOG.md +++ b/crates/egui_extras/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to the `egui_extras` integration will be noted in this file. ## Unreleased * Added `TableBuilder::vertical_scroll_offset`: method to set vertical scroll offset position for a table ([#1946](https://github.com/emilk/egui/pull/1946)). +* Added `RetainedImage::from_svg_bytes_with_size` to be able to specify a size for SVGs to be rasterized at. ## 0.19.0 - 2022-08-20 * MSRV (Minimum Supported Rust Version) is now `1.61.0` ([#1846](https://github.com/emilk/egui/pull/1846)). diff --git a/crates/egui_extras/src/image.rs b/crates/egui_extras/src/image.rs index 47d15f55..e33a0de2 100644 --- a/crates/egui_extras/src/image.rs +++ b/crates/egui_extras/src/image.rs @@ -1,5 +1,8 @@ use egui::{mutex::Mutex, TextureFilter, TextureOptions}; +#[cfg(feature = "svg")] +pub use usvg::FitTo; + /// An image to be shown in egui. /// /// Load once, and save somewhere in your app state. @@ -52,10 +55,7 @@ impl RetainedImage { /// On invalid image #[cfg(feature = "svg")] pub fn from_svg_bytes(debug_name: impl Into, svg_bytes: &[u8]) -> Result { - Ok(Self::from_color_image( - debug_name, - load_svg_bytes(svg_bytes)?, - )) + Self::from_svg_bytes_with_size(debug_name, svg_bytes, FitTo::Original) } /// Pass in the str of an SVG that you've loaded. @@ -67,6 +67,23 @@ impl RetainedImage { Self::from_svg_bytes(debug_name, svg_str.as_bytes()) } + /// Pass in the bytes of an SVG that you've loaded + /// and the scaling option to resize the SVG with + /// + /// # Errors + /// On invalid image + #[cfg(feature = "svg")] + pub fn from_svg_bytes_with_size( + debug_name: impl Into, + svg_bytes: &[u8], + size: FitTo, + ) -> Result { + Ok(Self::from_color_image( + debug_name, + load_svg_bytes_with_size(svg_bytes, size)?, + )) + } + /// Set the texture filters to use for the image. /// /// **Note:** If the texture has already been uploaded to the GPU, this will require @@ -200,29 +217,50 @@ pub fn load_image_bytes(image_bytes: &[u8]) -> Result /// On invalid image #[cfg(feature = "svg")] pub fn load_svg_bytes(svg_bytes: &[u8]) -> Result { + load_svg_bytes_with_size(svg_bytes, FitTo::Original) +} + +/// Load an SVG and rasterize it into an egui image with a scaling parameter. +/// +/// Requires the "svg" feature. +/// +/// # Errors +/// On invalid image +#[cfg(feature = "svg")] +pub fn load_svg_bytes_with_size( + svg_bytes: &[u8], + fit_to: FitTo, +) -> Result { let mut opt = usvg::Options::default(); opt.fontdb.load_system_fonts(); let rtree = usvg::Tree::from_data(svg_bytes, &opt.to_ref()).map_err(|err| err.to_string())?; let pixmap_size = rtree.svg_node().size.to_screen_size(); - let [w, h] = [pixmap_size.width(), pixmap_size.height()]; + let [w, h] = match fit_to { + FitTo::Original => [pixmap_size.width(), pixmap_size.height()], + FitTo::Size(w, h) => [w, h], + FitTo::Height(h) => [ + (pixmap_size.width() as f32 * (h as f32 / pixmap_size.height() as f32)) as u32, + h, + ], + FitTo::Width(w) => [ + w, + (pixmap_size.height() as f32 * (w as f32 / pixmap_size.width() as f32)) as u32, + ], + FitTo::Zoom(z) => [ + (pixmap_size.width() as f32 * z) as u32, + (pixmap_size.height() as f32 * z) as u32, + ], + }; let mut pixmap = tiny_skia::Pixmap::new(w, h) .ok_or_else(|| format!("Failed to create SVG Pixmap of size {}x{}", w, h))?; - resvg::render( - &rtree, - usvg::FitTo::Original, - Default::default(), - pixmap.as_mut(), - ) - .ok_or_else(|| "Failed to render SVG".to_owned())?; + resvg::render(&rtree, fit_to, Default::default(), pixmap.as_mut()) + .ok_or_else(|| "Failed to render SVG".to_owned())?; - let image = egui::ColorImage::from_rgba_unmultiplied( - [pixmap.width() as _, pixmap.height() as _], - pixmap.data(), - ); + let image = egui::ColorImage::from_rgba_unmultiplied([w as _, h as _], pixmap.data()); Ok(image) } diff --git a/examples/svg/src/main.rs b/examples/svg/src/main.rs index d272d67d..63baa552 100644 --- a/examples/svg/src/main.rs +++ b/examples/svg/src/main.rs @@ -25,9 +25,10 @@ struct MyApp { impl Default for MyApp { fn default() -> Self { Self { - svg_image: egui_extras::RetainedImage::from_svg_bytes( + svg_image: egui_extras::RetainedImage::from_svg_bytes_with_size( "rustacean-flat-happy.svg", include_bytes!("rustacean-flat-happy.svg"), + egui_extras::image::FitTo::Original, ) .unwrap(), } @@ -43,7 +44,7 @@ impl eframe::App for MyApp { ui.separator(); let max_size = ui.available_size(); - self.svg_image.show_max_size(ui, max_size); + self.svg_image.show_size(ui, max_size); }); } }