use std::sync::OnceLock;
use resvg::usvg;
use tiny_skia::{Color, Pixmap, Transform};
use crate::Figure;
static FONTDB: OnceLock<usvg::fontdb::Database> = OnceLock::new();
fn shared_fontdb() -> &'static usvg::fontdb::Database {
FONTDB.get_or_init(|| {
let mut db = usvg::fontdb::Database::new();
db.load_system_fonts();
db
})
}
pub(crate) fn to_pixmap(fig: &Figure, width: u32, height: u32) -> Vec<u8> {
assert!(width > 0 && height > 0, "to_pixmap requires non-zero dimensions");
let svg = fig.to_svg();
let mut opt = usvg::Options::default();
opt.fontdb = std::sync::Arc::new(shared_fontdb().clone());
let tree = usvg::Tree::from_str(&svg, &opt)
.expect("bland generates well-formed SVG; tree parse should be infallible");
let svg_size = tree.size();
let scale_x = width as f32 / svg_size.width();
let scale_y = height as f32 / svg_size.height();
let scale = scale_x.min(scale_y);
let mut pixmap = Pixmap::new(width, height).expect("non-zero dimensions checked above");
pixmap.fill(Color::WHITE);
resvg::render(&tree, Transform::from_scale(scale, scale), &mut pixmap.as_mut());
pixmap.data().to_vec()
}
#[cfg(test)]
mod tests {
use crate::Figure;
#[test]
fn to_pixmap_returns_correct_size() {
let fig = Figure::new()
.title("test")
.line(&[0.0, 1.0, 2.0], &[0.0, 1.0, 4.0], |s| s);
let buf = fig.to_pixmap(200, 150);
assert_eq!(buf.len(), 200 * 150 * 4);
}
#[test]
fn to_pixmap_fills_some_non_white_pixels() {
let fig = Figure::new().line(&[0.0, 1.0], &[0.0, 1.0], |s| s);
let buf = fig.to_pixmap(200, 150);
let any_drawn = buf
.chunks_exact(4)
.any(|px| !(px[0] == 255 && px[1] == 255 && px[2] == 255));
assert!(any_drawn, "rasterized figure should contain non-white pixels");
}
}