Created
February 8, 2022 20:43
-
-
Save emilk/455ac28ce9d7178f280204d26515bbc0 to your computer and use it in GitHub Desktop.
Using `nsvg` to show and SVG in egui.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! 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