Skip to content

Instantly share code, notes, and snippets.

@emilk
Created February 8, 2022 20:43
Show Gist options
  • Save emilk/455ac28ce9d7178f280204d26515bbc0 to your computer and use it in GitHub Desktop.
Save emilk/455ac28ce9d7178f280204d26515bbc0 to your computer and use it in GitHub Desktop.
Using `nsvg` to show and SVG in egui.
//! This uses `nsvg` to parse and rasterize an SVG image.
//!
//! Unfortunately `nsvg` does not preserve SVG size and aspect ratio :(
use eframe::{egui, epi};
struct Svg {
image: egui::ColorImage,
/// original size of the svg
svg_size: egui::Vec2,
}
impl Svg {
fn parse_svg_string(svg_str: &str) -> Result<Svg, nsvg::Error> {
let resolution = 1024.0;
let svg = nsvg::parse_str(svg_str, nsvg::Units::Pixel, 96.0)?;
// nsvg often reports size 1.0 x 1.0 :(
let svg_size = egui::vec2(svg.width(), svg.height());
let scale = resolution * svg_size.x.max(svg_size.y);
let (w, h, data) = svg.rasterize_to_raw_rgba(scale)?;
let image = egui::ColorImage::from_rgba_unmultiplied([w as _, h as _], &data);
let svg = Svg { image, svg_size };
Ok(svg)
}
}
struct MyApp {
svg: Svg,
svg_texture: Option<egui::TextureHandle>,
}
impl Default for MyApp {
fn default() -> Self {
Self {
svg: Svg::parse_svg_string(include_str!("rustacean-flat-happy.svg")).unwrap(),
svg_texture: None,
}
}
}
impl epi::App for MyApp {
fn name(&self) -> &str {
"svg example"
}
fn update(&mut self, ctx: &egui::Context, _frame: &epi::Frame) {
let svg_texture = self
.svg_texture
.get_or_insert_with(|| ctx.load_texture("svg", self.svg.image.clone()));
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("SVG example");
ui.label(format!(
"Original svg size: {:.1}x{:.1}. Rasterized size: {}x{}",
self.svg.svg_size.x,
self.svg.svg_size.y,
self.svg.image.width(),
self.svg.image.height()
));
ui.separator();
let max_size = ui.available_size();
let mut desired_size = svg_texture.size_vec2();
desired_size *= (max_size.x / desired_size.x).min(1.0);
desired_size *= (max_size.y / desired_size.y).min(1.0);
ui.image(svg_texture, desired_size);
});
}
}
fn main() {
let options = eframe::NativeOptions::default();
eframe::run_native(Box::new(MyApp::default()), options);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment