use std::sync::{Arc, OnceLock};
use crate::backend::svg::SvgBackend;
use crate::render::render::Scene;
fn shared_fontdb() -> Arc<resvg::usvg::fontdb::Database> {
static FONTDB: OnceLock<Arc<resvg::usvg::fontdb::Database>> = OnceLock::new();
FONTDB
.get_or_init(|| {
let mut db = resvg::usvg::fontdb::Database::new();
db.load_font_data(crate::fonts::dejavu_sans().to_vec());
db.load_system_fonts();
Arc::new(db)
})
.clone()
}
pub struct PngBackend {
pub scale: f32,
}
impl Default for PngBackend {
fn default() -> Self {
Self::new()
}
}
impl PngBackend {
pub fn new() -> Self {
Self { scale: 2.0 }
}
pub fn with_scale(mut self, scale: f32) -> Self {
self.scale = scale;
self
}
pub fn render_scene(&self, scene: &Scene) -> Result<Vec<u8>, String> {
let svg_str = SvgBackend.render_scene(scene);
let options = resvg::usvg::Options {
fontdb: shared_fontdb(),
..Default::default()
};
let tree = resvg::usvg::Tree::from_str(&svg_str, &options).map_err(|e| e.to_string())?;
let size = tree
.size()
.to_int_size()
.scale_by(self.scale)
.ok_or_else(|| "canvas too large for the requested scale factor".to_string())?;
let mut pixmap = resvg::tiny_skia::Pixmap::new(size.width(), size.height())
.ok_or_else(|| "failed to allocate pixmap".to_string())?;
let transform = resvg::tiny_skia::Transform::from_scale(self.scale, self.scale);
resvg::render(&tree, transform, &mut pixmap.as_mut());
pixmap.encode_png().map_err(|e| e.to_string())
}
}