use std::sync::Arc;
use image::{DynamicImage, RgbaImage};
use usvg::{NodeExt, Rect};
use crate::Error;
fn calc_node_bbox(
tree: &usvg::Tree,
node: &usvg::Node,
ts: usvg::Transform,
) -> Option<usvg::PathBbox> {
match *node.borrow() {
usvg::NodeKind::Path(ref path) => path.data.bbox_with_transform(ts, path.stroke.as_ref()),
usvg::NodeKind::Image(ref img) => {
let path = usvg::PathData::from_rect(img.view_box.rect);
path.bbox_with_transform(ts, None)
}
usvg::NodeKind::Svg(_) => {
let mut bbox = usvg::PathBbox::new_bbox();
for child in node.children() {
let mut child_tx = ts.clone();
child_tx.append(&child.transform());
if let Some(c_bbox) = calc_node_bbox(tree, &child, child_tx) {
bbox = bbox.expand(c_bbox);
}
}
Some(bbox)
}
usvg::NodeKind::Group(usvg::Group { ref filter, .. }) => {
let mut bbox = usvg::PathBbox::new_bbox();
for child in node.children() {
let mut child_tx = ts.clone();
child_tx.append(&child.transform());
if let Some(c_bbox) = calc_node_bbox(tree, &child, child_tx) {
bbox = bbox.expand(c_bbox);
}
}
for f in filter {
if let Some(def) = tree.defs_by_id(f.as_str()) {
match *def.borrow() {
usvg::NodeKind::Filter(ref x) => {
bbox = bbox.expand(x.rect.to_path_bbox());
}
_ => (),
}
}
}
Some(bbox)
}
_ => None,
}
}
fn rasterize(tree: &usvg::Tree, bbox: &Rect, sf: f32) -> Result<(DynamicImage, Vec<u8>), Error> {
let mut img = tiny_skia::Pixmap::new(
(bbox.width() as f32 * sf) as u32,
(bbox.height() as f32 * sf) as u32,
)
.ok_or(usvg::Error::InvalidSize)?;
resvg::render(
&tree,
usvg::FitTo::Original,
tiny_skia::Transform::from_translate(-bbox.x() as f32, -bbox.y() as f32).post_scale(sf, sf),
img.as_mut(),
);
let encoded_bytes = img.encode_png().ok().ok_or(usvg::Error::InvalidSize)?;
let raw_img = RgbaImage::from_raw(img.width(), img.height(), img.data().to_vec())
.ok_or(usvg::Error::InvalidSize)?;
Ok((DynamicImage::ImageRgba8(raw_img), encoded_bytes))
}
pub struct RasterizedVector {
pub content_box: Rect,
pub encoded_bytes_1x: Arc<serde_bytes::ByteBuf>,
pub encoded_bytes_2x: Arc<serde_bytes::ByteBuf>,
pub encoded_bytes_3x: Arc<serde_bytes::ByteBuf>,
pub width: u32,
pub height: u32,
}
pub fn render_svg_without_clip(svg_content: &str) -> Result<RasterizedVector, Error> {
let tree = usvg::Tree::from_str(svg_content, &usvg::Options { ..Default::default() }.to_ref())?;
let svg_node = tree.svg_node();
let bbox = {
let bbox = calc_node_bbox(&tree, &tree.root(), usvg::Transform::default())
.ok_or(usvg::Error::InvalidSize)?
.expand(
usvg::PathBbox::new(0.0, 0.0, svg_node.size.width(), svg_node.size.height())
.ok_or(usvg::Error::InvalidSize)?,
);
let x = bbox.x().floor();
let y = bbox.y().floor();
let w = bbox.right().ceil() - x;
let h = bbox.bottom().ceil() - y;
Rect::new(x, y, w, h).ok_or(usvg::Error::InvalidSize)?
};
let (img, encoded_bytes_1x) = rasterize(&tree, &bbox, 1.0)?;
let (_, encoded_bytes_2x) = rasterize(&tree, &bbox, 2.0)?;
let (_, encoded_bytes_3x) = rasterize(&tree, &bbox, 3.0)?;
Ok(RasterizedVector {
content_box: bbox,
encoded_bytes_1x: Arc::new(serde_bytes::ByteBuf::from(encoded_bytes_1x)),
encoded_bytes_2x: Arc::new(serde_bytes::ByteBuf::from(encoded_bytes_2x)),
encoded_bytes_3x: Arc::new(serde_bytes::ByteBuf::from(encoded_bytes_3x)),
width: img.width(),
height: img.height(),
})
}