use super::{
super::{format::*, image::Image, stream::*},
zlib::*,
};
use {
resvg::*,
std::{
fs::*,
io,
path::{Path, *},
},
tiny_skia::*,
usvg::*,
};
impl Image {
pub fn new_owned_from_svg_file<PathT>(
path: PathT,
format: ImageFormat,
scale: f64,
compress: bool,
) -> io::Result<Self>
where
PathT: AsRef<Path>,
{
let tree = read_svg(path)?;
let size = size(&tree, scale)?;
let data = render_svg(tree, format, scale)?;
let data = if compress { zlib(&data)? } else { data };
Ok(Self::new_owned(data, compress, format, (size.width(), size.height())))
}
pub fn new_stream_from_svg_file<PathT>(path: PathT, format: ImageFormat, scale: f64) -> io::Result<Self>
where
PathT: AsRef<Path>,
{
let path = path.as_ref();
let tree = read_svg(path)?;
let size = size(&tree, scale)?;
let stream = SvgImageStream::new(path.into(), format, scale);
Ok(Self::new_stream(stream, format, (size.width(), size.height())))
}
}
struct SvgImageStream {
path: PathBuf,
format: ImageFormat,
scale: f64,
}
impl SvgImageStream {
fn new(path: PathBuf, format: ImageFormat, scale: f64) -> Self {
Self { path, format, scale }
}
}
impl ImageStream for SvgImageStream {
fn open(&self) -> io::Result<(Box<dyn io::Read>, bool)> {
let tree = read_svg(&self.path)?;
let data = render_svg(tree, self.format, self.scale)?;
Ok((Box::new(io::Cursor::new(data)), false))
}
}
fn read_svg<PathT>(path: PathT) -> io::Result<Tree>
where
PathT: AsRef<Path>,
{
let data = read(path.as_ref())?;
let mut options = Options::default();
options.fontdb_mut().load_system_fonts();
Ok(Tree::from_data(&data, &options).map_err(io::Error::other)?)
}
fn render_svg(tree: Tree, format: ImageFormat, scale: f64) -> io::Result<Vec<u8>> {
let size = size(&tree, scale)?;
let mut pixmap =
Pixmap::new(size.width(), size.height()).ok_or_else(|| io::Error::other("cannot create Pixmap"))?;
let scale = scale as f32;
render(&tree, Transform::from_scale(scale, scale), &mut pixmap.as_mut());
Ok(match format {
ImageFormat::PNG => pixmap.encode_png()?,
ImageFormat::RGBA => pixmap.take(),
_ => return Err(io::Error::other("unsupported format")),
})
}
fn size(tree: &Tree, scale: f64) -> io::Result<IntSize> {
Ok(tree.size().scale_by(scale as f32).ok_or_else(|| io::Error::other("scaling error"))?.to_int_size())
}