From 4a3591695902f027e350cdec8074e32532844ce3 Mon Sep 17 00:00:00 2001 From: Zimond Date: Mon, 25 Sep 2023 10:42:25 +0800 Subject: [PATCH] load sub svg in resvg --- crates/resvg/src/image.rs | 8 +++-- crates/usvg-parser/src/filter.rs | 2 +- crates/usvg-parser/src/image.rs | 50 +++++++++++++++--------------- crates/usvg-parser/src/lib.rs | 2 +- crates/usvg-text-layout/src/lib.rs | 10 +++--- crates/usvg-tree/Cargo.toml | 1 + crates/usvg-tree/src/lib.rs | 9 +++--- crates/usvg/src/writer.rs | 10 +++--- 8 files changed, 48 insertions(+), 44 deletions(-) diff --git a/crates/resvg/src/image.rs b/crates/resvg/src/image.rs index 5b59baf37..5d8e6cb18 100644 --- a/crates/resvg/src/image.rs +++ b/crates/resvg/src/image.rs @@ -2,6 +2,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. +use usvg::load_sub_svg; + use crate::render::TinySkiaPixmapMutExt; use crate::tree::{BBoxes, Node, Tree}; @@ -34,7 +36,9 @@ pub fn convert(image: &usvg::Image, children: &mut Vec) -> Option } let kind = match image.kind { - usvg::ImageKind::SVG(_) => return None, + usvg::ImageKind::SVG(ref data) => ImageKind::Vector(Tree::from_usvg( + &load_sub_svg(&data, &usvg::Options::default()).unwrap(), + )), #[cfg(feature = "raster-images")] _ => ImageKind::Raster(raster_images::decode_raster(image)?), #[cfg(not(feature = "raster-images"))] @@ -105,8 +109,6 @@ fn render_vector( #[cfg(feature = "raster-images")] mod raster_images { - use usvg::fontdb::Database; - use super::Image; use crate::render::TinySkiaPixmapMutExt; use crate::tree::OptionLog; diff --git a/crates/usvg-parser/src/filter.rs b/crates/usvg-parser/src/filter.rs index 06218b819..e72ccc472 100644 --- a/crates/usvg-parser/src/filter.rs +++ b/crates/usvg-parser/src/filter.rs @@ -56,7 +56,7 @@ pub(crate) fn convert( _ => NonZeroRect::from_xywh(-0.1, -0.1, 1.2, 1.2).unwrap(), }; - filters.push(Rc::new(Filter { + filters.push(Arc::new(Filter { id: String::new(), units: Units::ObjectBoundingBox, primitive_units: Units::UserSpaceOnUse, diff --git a/crates/usvg-parser/src/image.rs b/crates/usvg-parser/src/image.rs index f2be710ea..fe4402c02 100644 --- a/crates/usvg-parser/src/image.rs +++ b/crates/usvg-parser/src/image.rs @@ -54,7 +54,7 @@ impl ImageHrefResolver { /// The actual images would not be decoded. It's up to the renderer. pub fn default_data_resolver() -> ImageHrefDataResolverFn { Arc::new( - move |mime: &str, data: Arc>, opts: &Options| match mime { + move |mime: &str, data: Arc>, _opts: &Options| match mime { "image/jpg" | "image/jpeg" => Some(ImageKind::JPEG(data)), "image/png" => Some(ImageKind::PNG(data)), "image/gif" => Some(ImageKind::GIF(data)), @@ -69,12 +69,12 @@ impl ImageHrefResolver { let height: u32 = u32::from_be_bytes(height_vec); Some(ImageKind::RAW(width, height, Arc::new(buf.to_vec()))) } - "image/svg+xml" => load_sub_svg(&data, opts), + "image/svg+xml" => Some(ImageKind::SVG(Arc::new(data.to_vec()))), "text/plain" => match get_image_data_format(&data) { Some(ImageFormat::JPEG) => Some(ImageKind::JPEG(data)), Some(ImageFormat::PNG) => Some(ImageKind::PNG(data)), Some(ImageFormat::GIF) => Some(ImageKind::GIF(data)), - _ => load_sub_svg(&data, opts), + _ => Some(ImageKind::SVG(Arc::new(data.to_vec()))), }, _ => None, }, @@ -105,7 +105,7 @@ impl ImageHrefResolver { Some(ImageFormat::JPEG) => Some(ImageKind::JPEG(Arc::new(data))), Some(ImageFormat::PNG) => Some(ImageKind::PNG(Arc::new(data))), Some(ImageFormat::GIF) => Some(ImageKind::GIF(Arc::new(data))), - Some(ImageFormat::SVG) => load_sub_svg(&data, opts), + Some(ImageFormat::SVG) => Some(ImageKind::SVG(Arc::new(data))), _ => { log::warn!("'{}' is not a PNG, JPEG, GIF or SVG(Z) image.", href); None @@ -249,27 +249,27 @@ fn get_image_data_format(data: &[u8]) -> Option { /// /// Unlike `Tree::from_*` methods, this one will also remove all `image` elements /// from the loaded SVG, as required by the spec. -pub(crate) fn load_sub_svg(data: &[u8], _: &Options) -> Option { - // let mut sub_opt = Options::default(); - // sub_opt.resources_dir = None; - // sub_opt.dpi = opt.dpi; - // sub_opt.font_size = opt.font_size; - // sub_opt.languages = opt.languages.clone(); - // sub_opt.shape_rendering = opt.shape_rendering; - // sub_opt.text_rendering = opt.text_rendering; - // sub_opt.image_rendering = opt.image_rendering; - // sub_opt.default_size = opt.default_size; - - // let tree = match Tree::from_data(data, &sub_opt) { - // Ok(tree) => tree, - // Err(_) => { - // log::warn!("Failed to load subsvg image."); - // return None; - // } - // }; - - // sanitize_sub_svg(&tree); - Some(ImageKind::SVG(Arc::new(data.to_vec()))) +pub fn load_sub_svg(data: &[u8], opt: &Options) -> Option { + let mut sub_opt = Options::default(); + sub_opt.resources_dir = None; + sub_opt.dpi = opt.dpi; + sub_opt.font_size = opt.font_size; + sub_opt.languages = opt.languages.clone(); + sub_opt.shape_rendering = opt.shape_rendering; + sub_opt.text_rendering = opt.text_rendering; + sub_opt.image_rendering = opt.image_rendering; + sub_opt.default_size = opt.default_size; + + let tree = match Tree::from_data(data, &sub_opt) { + Ok(tree) => tree, + Err(_) => { + log::warn!("Failed to load subsvg image."); + return None; + } + }; + + sanitize_sub_svg(&tree); + Some(tree) } // TODO: technically can simply override Options::image_href_resolver? diff --git a/crates/usvg-parser/src/lib.rs b/crates/usvg-parser/src/lib.rs index 64a789617..d5220bca4 100644 --- a/crates/usvg-parser/src/lib.rs +++ b/crates/usvg-parser/src/lib.rs @@ -38,7 +38,7 @@ mod units; mod use_node; pub use crate::options::*; -pub use image::ImageHrefResolver; +pub use image::{load_sub_svg, ImageHrefResolver}; pub use roxmltree; pub use svgtree::{AId, EId}; diff --git a/crates/usvg-text-layout/src/lib.rs b/crates/usvg-text-layout/src/lib.rs index a4ff96dd0..aea3571b2 100644 --- a/crates/usvg-text-layout/src/lib.rs +++ b/crates/usvg-text-layout/src/lib.rs @@ -55,11 +55,11 @@ fn convert_text(root: Node, fontdb: &fontdb::Database) { text_nodes.push(node.clone()); } - if let NodeKind::Image(ref mut image) = *node.borrow_mut() { - if let ImageKind::SVG(ref mut tree) = image.kind { - tree.convert_text(fontdb); - } - } + // if let NodeKind::Image(ref mut image) = *node.borrow_mut() { + // if let ImageKind::SVG(ref mut tree) = image.kind { + // tree.convert_text(fontdb); + // } + // } node.subroots(|subroot| convert_text(subroot, fontdb)) } diff --git a/crates/usvg-tree/Cargo.toml b/crates/usvg-tree/Cargo.toml index aee5a3eb0..7fd3fcfbe 100644 --- a/crates/usvg-tree/Cargo.toml +++ b/crates/usvg-tree/Cargo.toml @@ -13,6 +13,7 @@ readme = "README.md" workspace = "../.." [dependencies] +kurbo = "0.9.5" rctree = "0.5" strict-num = "0.1.1" svgtypes = "0.13" diff --git a/crates/usvg-tree/src/lib.rs b/crates/usvg-tree/src/lib.rs index d0e1b9356..32b966d1e 100644 --- a/crates/usvg-tree/src/lib.rs +++ b/crates/usvg-tree/src/lib.rs @@ -893,7 +893,7 @@ pub enum ImageKind { /// A preprocessed SVG tree. Can be rendered as is. SVG(Arc>), /// RAW image data - RAW(u32, u32, Arc>) + RAW(u32, u32, Arc>), } impl std::fmt::Debug for ImageKind { @@ -1034,9 +1034,10 @@ fn has_text_nodes(root: &Node) -> bool { if let NodeKind::Image(ref image) = *node.borrow() { if let ImageKind::SVG(ref tree) = image.kind { - if has_text_nodes(&tree.root) { - has_text = true; - } + // if has_text_nodes(&tree.root) { + // has_text = true; + // } + has_text = false; } } diff --git a/crates/usvg/src/writer.rs b/crates/usvg/src/writer.rs index 23d375d2a..5bd7ff828 100644 --- a/crates/usvg/src/writer.rs +++ b/crates/usvg/src/writer.rs @@ -138,22 +138,22 @@ impl WriterContext<'_> { id } - fn push_defs_id(&mut self, node: &Rc, id: String) { - let key = Rc::as_ptr(node) as usize; + fn push_defs_id(&mut self, node: &Arc, id: String) { + let key = Arc::as_ptr(node) as usize; if !self.id_map.contains_key(&key) { self.id_map.insert(key, id); } } - fn get_defs_id(&self, node: &Rc) -> Option<&str> { - let key = Rc::as_ptr(node) as usize; + fn get_defs_id(&self, node: &Arc) -> Option<&str> { + let key = Arc::as_ptr(node) as usize; debug_assert!(self.id_map.contains_key(&key)); self.id_map.get(&key).map(|v| v.as_str()) } fn prepare_defs_id String>( &mut self, - node: &Rc, + node: &Arc, id: &str, xml: &mut XmlWriter, f: F,