cursive_image/image/compatibility/
svg.rs1use super::{
2 super::{format::*, image::Image, stream::*},
3 zlib::*,
4};
5
6use {
7 resvg::*,
8 std::{
9 fs::*,
10 io,
11 path::{Path, *},
12 },
13 tiny_skia::*,
14 usvg::*,
15};
16
17impl Image {
18 pub fn new_owned_from_svg_file<PathT>(
22 path: PathT,
23 format: ImageFormat,
24 scale: f64,
25 compress: bool,
26 ) -> io::Result<Self>
27 where
28 PathT: AsRef<Path>,
29 {
30 let tree = read_svg(path)?;
31 let size = size(&tree, scale)?;
32 let data = render_svg(tree, format, scale)?;
33 let data = if compress { zlib(&data)? } else { data };
34 Ok(Self::new_owned(data, compress, format, (size.width(), size.height())))
35 }
36
37 pub fn new_stream_from_svg_file<PathT>(path: PathT, format: ImageFormat, scale: f64) -> io::Result<Self>
41 where
42 PathT: AsRef<Path>,
43 {
44 let path = path.as_ref();
45 let tree = read_svg(path)?;
46 let size = size(&tree, scale)?;
47 let stream = SvgImageStream::new(path.into(), format, scale);
48 Ok(Self::new_stream(stream, format, (size.width(), size.height())))
49 }
50}
51
52struct SvgImageStream {
57 path: PathBuf,
58 format: ImageFormat,
59 scale: f64,
60}
61
62impl SvgImageStream {
63 fn new(path: PathBuf, format: ImageFormat, scale: f64) -> Self {
64 Self { path, format, scale }
65 }
66}
67
68impl ImageStream for SvgImageStream {
69 fn open(&self) -> io::Result<(Box<dyn io::Read>, bool)> {
70 let tree = read_svg(&self.path)?;
72 let data = render_svg(tree, self.format, self.scale)?;
73 Ok((Box::new(io::Cursor::new(data)), false))
74 }
75}
76
77fn read_svg<PathT>(path: PathT) -> io::Result<Tree>
80where
81 PathT: AsRef<Path>,
82{
83 let data = read(path.as_ref())?;
84
85 let mut options = Options::default();
86 options.fontdb_mut().load_system_fonts();
87
88 Ok(Tree::from_data(&data, &options).map_err(io::Error::other)?)
94}
95
96fn render_svg(tree: Tree, format: ImageFormat, scale: f64) -> io::Result<Vec<u8>> {
97 let size = size(&tree, scale)?;
98 let mut pixmap =
99 Pixmap::new(size.width(), size.height()).ok_or_else(|| io::Error::other("cannot create Pixmap"))?;
100 let scale = scale as f32;
101 render(&tree, Transform::from_scale(scale, scale), &mut pixmap.as_mut());
102
103 Ok(match format {
104 ImageFormat::PNG => pixmap.encode_png()?,
105 ImageFormat::RGBA => pixmap.take(),
106 _ => return Err(io::Error::other("unsupported format")),
107 })
108}
109
110fn size(tree: &Tree, scale: f64) -> io::Result<IntSize> {
111 Ok(tree.size().scale_by(scale as f32).ok_or_else(|| io::Error::other("scaling error"))?.to_int_size())
112}