refilelabs-image 0.3.1

Wasm-based image processing library developed by re;file labs
Documentation
use resvg::render;
use resvg::tiny_skia::{IntSize, Pixmap};
use resvg::usvg::{Options, Size, Transform, Tree};

use super::settings::SvgSettings;
use crate::error::WasmImageError;

pub(crate) fn svg_to_png(svg: &[u8], svg_settings: SvgSettings) -> Result<Vec<u8>, WasmImageError> {
    let SvgSettings { width, height } = svg_settings;

    let options = Options {
        dpi: 96.0,
        shape_rendering: resvg::usvg::ShapeRendering::GeometricPrecision,
        text_rendering: resvg::usvg::TextRendering::OptimizeLegibility,
        image_rendering: resvg::usvg::ImageRendering::OptimizeQuality,
        default_size: Size::from_wh(width as f32, height as f32).unwrap(),
        ..Default::default()
    };

    let tree = Tree::from_data(svg, &options)?;

    let original_svg_size = tree.size().to_int_size();
    let original_svg_size_f32 = original_svg_size.to_size();
    let fit_to_size = IntSize::from_wh(width, height).map(|s| original_svg_size.scale_to(s));
    let scaled_svg_size = match fit_to_size {
        Some(v) => v.to_size(),
        None => original_svg_size.to_size(),
    };

    let transform = Transform::from_scale(
        scaled_svg_size.width() / original_svg_size_f32.width(),
        scaled_svg_size.height() / original_svg_size_f32.height(),
    );

    let mut pixmap = Pixmap::new(width, height)
        .ok_or(WasmImageError::SvgError(resvg::usvg::Error::InvalidSize))?;

    render(&tree, transform, &mut pixmap.as_mut());

    pixmap
        .encode_png()
        .map_err(|e| WasmImageError::EncodingError(e.to_string()))
}

#[cfg(test)]
mod tests {
    use super::*;
    use image::{GenericImageView, ImageFormat};

    #[test]
    fn test_rasterize_svg() {
        let svg = include_bytes!("../../assets/test.svg");

        let result = svg_to_png(svg, SvgSettings::default()).unwrap();

        let img = image::load_from_memory_with_format(&result, ImageFormat::Png).unwrap();

        assert_eq!(img.dimensions(), (100, 100));
    }
}