feat: add a way to provide customable scaling to SVG rasterization (#2252)
This commit is contained in:
parent
b3ab47a594
commit
3805a3282f
3 changed files with 58 additions and 18 deletions
|
@ -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)).
|
||||
|
|
|
@ -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<String>, svg_bytes: &[u8]) -> Result<Self, String> {
|
||||
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<String>,
|
||||
svg_bytes: &[u8],
|
||||
size: FitTo,
|
||||
) -> Result<Self, String> {
|
||||
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<egui::ColorImage, String>
|
|||
/// On invalid image
|
||||
#[cfg(feature = "svg")]
|
||||
pub fn load_svg_bytes(svg_bytes: &[u8]) -> Result<egui::ColorImage, String> {
|
||||
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<egui::ColorImage, String> {
|
||||
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(),
|
||||
)
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue