Bump resvg + svg2pdf and add support for filters (#3254)
This commit is contained in:
parent
cd71741532
commit
afc28264e8
31
Cargo.lock
generated
31
Cargo.lock
generated
@ -1735,12 +1735,6 @@ dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rctree"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b42e27ef78c35d3998403c1d26f3efd9e135d3e5121b0a4845cc5cc27547f4f"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
@ -1798,9 +1792,9 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "resvg"
|
||||
version = "0.37.0"
|
||||
version = "0.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cadccb3d99a9efb8e5e00c16fbb732cbe400db2ec7fc004697ee7d97d86cf1f4"
|
||||
checksum = "5c34501046959e06470ba62a2dc7f31c15f94ac250d842a45f9e012f4ee40c1e"
|
||||
dependencies = [
|
||||
"gif",
|
||||
"jpeg-decoder",
|
||||
@ -2170,12 +2164,14 @@ checksum = "09eab8a83bff89ba2200bd4c59be45c7c787f988431b936099a5a266c957f2f9"
|
||||
[[package]]
|
||||
name = "svg2pdf"
|
||||
version = "0.9.1"
|
||||
source = "git+https://github.com/typst/svg2pdf?rev=11f34c7#11f34c7f407d504c49db19e4e2b521fce4c8622f"
|
||||
source = "git+https://github.com/typst/svg2pdf?rev=49891ef#49891ef48eee1a03f2ed090541d88fd0193bf2c9"
|
||||
dependencies = [
|
||||
"image",
|
||||
"miniz_oxide",
|
||||
"once_cell",
|
||||
"pdf-writer",
|
||||
"resvg",
|
||||
"tiny-skia",
|
||||
"usvg",
|
||||
]
|
||||
|
||||
@ -2859,9 +2855,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "usvg"
|
||||
version = "0.37.0"
|
||||
version = "0.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38b0a51b72ab80ca511d126b77feeeb4fb1e972764653e61feac30adc161a756"
|
||||
checksum = "377f62b4a3c173de8654c1aa80ab1dac1154e6f13a779a9943e53780120d1625"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"log",
|
||||
@ -2874,9 +2870,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "usvg-parser"
|
||||
version = "0.37.0"
|
||||
version = "0.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bd4e3c291f45d152929a31f0f6c819245e2921bfd01e7bd91201a9af39a2bdc"
|
||||
checksum = "351a05e6f2023d6b4e946f734240a3927aefdcf930d7d42587a2c8a8869814b0"
|
||||
dependencies = [
|
||||
"data-url",
|
||||
"flate2",
|
||||
@ -2892,9 +2888,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "usvg-text-layout"
|
||||
version = "0.37.0"
|
||||
version = "0.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d383a3965de199d7f96d4e11a44dd859f46e86de7f3dca9a39bf82605da0a37c"
|
||||
checksum = "8c41888b9d5cf431fe852eaf9d047bbde83251b98f1749c2f08b1071e6db46e2"
|
||||
dependencies = [
|
||||
"fontdb",
|
||||
"kurbo",
|
||||
@ -2908,11 +2904,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "usvg-tree"
|
||||
version = "0.37.0"
|
||||
version = "0.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ee3d202ebdb97a6215604b8f5b4d6ef9024efd623cf2e373a6416ba976ec7d3"
|
||||
checksum = "18863e0404ed153d6e56362c5b1146db9f4f262a3244e3cf2dbe7d8a85909f05"
|
||||
dependencies = [
|
||||
"rctree",
|
||||
"strict-num",
|
||||
"svgtypes",
|
||||
"tiny-skia-path",
|
||||
|
@ -76,7 +76,7 @@ pulldown-cmark = "0.9"
|
||||
quote = "1"
|
||||
rayon = "1.7.0"
|
||||
regex = "1"
|
||||
resvg = { version = "0.37.0", default-features = false, features = ["raster-images"] }
|
||||
resvg = { version = "0.38.0", default-features = false, features = ["raster-images"] }
|
||||
roxmltree = "0.19"
|
||||
rustls = "0.21" # in sync with ureq
|
||||
rustls-pemfile = "1" # in sync with rustls
|
||||
@ -91,7 +91,7 @@ siphasher = "1"
|
||||
smallvec = { version = "1.11.1", features = ["union", "const_generics", "const_new"] }
|
||||
stacker = "0.1.15"
|
||||
subsetter = "0.1.1"
|
||||
svg2pdf = { git = "https://github.com/typst/svg2pdf", rev = "11f34c7" }
|
||||
svg2pdf = { git = "https://github.com/typst/svg2pdf", rev = "49891ef" }
|
||||
syn = { version = "2", features = ["full", "extra-traits"] }
|
||||
syntect = { version = "5", default-features = false, features = ["parsing", "regex-fancy", "plist-load", "yaml-load"] }
|
||||
tar = "0.4"
|
||||
@ -111,7 +111,7 @@ unicode-script = "0.5"
|
||||
unicode-segmentation = "1"
|
||||
unscanny = "0.1"
|
||||
ureq = "2"
|
||||
usvg = { version = "0.37", default-features = false, features = ["text"] }
|
||||
usvg = { version = "0.38.0", default-features = false, features = ["text"] }
|
||||
walkdir = "2"
|
||||
wasmi = "0.31.0"
|
||||
xmlparser = "0.13.5"
|
||||
|
@ -19,7 +19,7 @@ use typst::visualize::{
|
||||
Color, DashPattern, FixedStroke, Geometry, Gradient, Image, ImageKind, LineCap,
|
||||
LineJoin, Paint, Path, PathItem, Pattern, RasterFormat, RelativeTo, Shape,
|
||||
};
|
||||
use usvg::{NodeExt, TreeParsing};
|
||||
use usvg::TreeParsing;
|
||||
|
||||
/// Export a frame into a raster image.
|
||||
///
|
||||
@ -272,8 +272,8 @@ fn render_svg_glyph(
|
||||
|
||||
// Parse SVG.
|
||||
let opts = usvg::Options::default();
|
||||
let usvg_tree = usvg::Tree::from_xmltree(&document, &opts).ok()?;
|
||||
let tree = resvg::Tree::from_usvg(&usvg_tree);
|
||||
let mut tree = usvg::Tree::from_xmltree(&document, &opts).ok()?;
|
||||
tree.calculate_bounding_boxes();
|
||||
let view_box = tree.view_box.rect;
|
||||
|
||||
// If there's no viewbox defined, use the em square for our scale
|
||||
@ -298,10 +298,8 @@ fn render_svg_glyph(
|
||||
// See https://github.com/RazrFalcon/resvg/issues/602 for why
|
||||
// using the svg size is problematic here.
|
||||
let mut bbox = usvg::BBox::default();
|
||||
for node in usvg_tree.root.descendants() {
|
||||
if let Some(rect) = node.calculate_bbox() {
|
||||
bbox = bbox.expand(rect);
|
||||
}
|
||||
if let Some(tree_bbox) = tree.root.bounding_box {
|
||||
bbox = bbox.expand(tree_bbox);
|
||||
}
|
||||
|
||||
// Compute the bbox after the transform is applied.
|
||||
@ -320,7 +318,7 @@ fn render_svg_glyph(
|
||||
|
||||
// We offset our transform so that the pixmap starts at the edge of the bbox.
|
||||
let ts = ts.post_translate(-bbox.left() as f32, -bbox.top() as f32);
|
||||
tree.render(ts, &mut pixmap.as_mut());
|
||||
resvg::render(&tree, ts, &mut pixmap.as_mut());
|
||||
|
||||
canvas.draw_pixmap(
|
||||
bbox.left(),
|
||||
@ -757,12 +755,11 @@ fn scaled_texture(image: &Image, w: u32, h: u32) -> Option<Arc<sk::Pixmap>> {
|
||||
// of `with`.
|
||||
ImageKind::Svg(svg) => unsafe {
|
||||
svg.with(|tree| {
|
||||
let tree = resvg::Tree::from_usvg(tree);
|
||||
let ts = tiny_skia::Transform::from_scale(
|
||||
w as f32 / tree.size.width(),
|
||||
h as f32 / tree.size.height(),
|
||||
);
|
||||
tree.render(ts, &mut pixmap.as_mut())
|
||||
resvg::render(tree, ts, &mut pixmap.as_mut())
|
||||
});
|
||||
},
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use std::sync::Arc;
|
||||
use comemo::Tracked;
|
||||
use ecow::EcoString;
|
||||
use siphasher::sip128::Hasher128;
|
||||
use usvg::{NodeExt, TreeParsing, TreeTextToPath};
|
||||
use usvg::{Node, PostProcessingSteps, TreeParsing, TreePostProc};
|
||||
|
||||
use crate::diag::{format_xml_like_error, StrResult};
|
||||
use crate::foundations::Bytes;
|
||||
@ -56,10 +56,11 @@ impl SvgImage {
|
||||
let mut tree = usvg::Tree::from_data(&data, &opts).map_err(format_usvg_error)?;
|
||||
let mut font_hash = 0;
|
||||
if tree.has_text_nodes() {
|
||||
let (fontdb, hash) = load_svg_fonts(world, &tree, families);
|
||||
tree.convert_text(&fontdb);
|
||||
let (fontdb, hash) = load_svg_fonts(world, &mut tree, families);
|
||||
tree.postprocess(PostProcessingSteps::default(), &fontdb);
|
||||
font_hash = hash;
|
||||
}
|
||||
tree.calculate_bounding_boxes();
|
||||
Ok(Self(Arc::new(Repr {
|
||||
data,
|
||||
size: tree_size(&tree),
|
||||
@ -128,7 +129,7 @@ impl Hash for Repr {
|
||||
/// Discover and load the fonts referenced by an SVG.
|
||||
fn load_svg_fonts(
|
||||
world: Tracked<dyn World + '_>,
|
||||
tree: &usvg::Tree,
|
||||
tree: &mut usvg::Tree,
|
||||
families: &[String],
|
||||
) -> (fontdb::Database, u128) {
|
||||
let book = world.book();
|
||||
@ -153,56 +154,70 @@ fn load_svg_fonts(
|
||||
};
|
||||
|
||||
// Determine the best font for each text node.
|
||||
traverse_svg(&tree.root, &mut |node| {
|
||||
let usvg::NodeKind::Text(text) = &mut *node.borrow_mut() else { return };
|
||||
for chunk in &mut text.chunks {
|
||||
'spans: for span in &mut chunk.spans {
|
||||
let Some(text) = chunk.text.get(span.start..span.end) else { continue };
|
||||
let variant = FontVariant {
|
||||
style: span.font.style.into(),
|
||||
weight: FontWeight::from_number(span.font.weight),
|
||||
stretch: span.font.stretch.into(),
|
||||
};
|
||||
|
||||
// Find a font that covers the whole text among the span's fonts
|
||||
// and the current document font families.
|
||||
let mut like = None;
|
||||
for family in span.font.families.iter().chain(families) {
|
||||
let Some(id) = book.select(&family.to_lowercase(), variant) else {
|
||||
for child in &mut tree.root.children {
|
||||
traverse_svg(child, &mut |node| {
|
||||
let usvg::Node::Text(ref mut text) = node else { return };
|
||||
for chunk in &mut text.chunks {
|
||||
'spans: for span in &mut chunk.spans {
|
||||
let Some(text) = chunk.text.get(span.start..span.end) else {
|
||||
continue;
|
||||
};
|
||||
let Some(info) = book.info(id) else { continue };
|
||||
like.get_or_insert(info);
|
||||
let variant = FontVariant {
|
||||
style: span.font.style.into(),
|
||||
weight: FontWeight::from_number(span.font.weight),
|
||||
stretch: span.font.stretch.into(),
|
||||
};
|
||||
|
||||
if text.chars().all(|c| info.coverage.contains(c as u32)) {
|
||||
// Find a font that covers the whole text among the span's fonts
|
||||
// and the current document font families.
|
||||
let mut like = None;
|
||||
for family in span.font.families.iter().chain(families) {
|
||||
let Some(id) = book.select(&family.to_lowercase(), variant)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let Some(info) = book.info(id) else { continue };
|
||||
like.get_or_insert(info);
|
||||
|
||||
if text.chars().all(|c| info.coverage.contains(c as u32)) {
|
||||
if let Some(usvg_family) = load_into_db(id) {
|
||||
span.font.families = vec![usvg_family];
|
||||
continue 'spans;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't find a match, select a fallback font.
|
||||
if let Some(id) = book.select_fallback(like, variant, text) {
|
||||
if let Some(usvg_family) = load_into_db(id) {
|
||||
span.font.families = vec![usvg_family];
|
||||
continue 'spans;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't find a match, select a fallback font.
|
||||
if let Some(id) = book.select_fallback(like, variant, text) {
|
||||
if let Some(usvg_family) = load_into_db(id) {
|
||||
span.font.families = vec![usvg_family];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
(fontdb, hasher.finish128().as_u128())
|
||||
}
|
||||
|
||||
/// Search for all font families referenced by an SVG.
|
||||
fn traverse_svg<F>(node: &usvg::Node, f: &mut F)
|
||||
fn traverse_svg<F>(node: &mut usvg::Node, f: &mut F)
|
||||
where
|
||||
F: FnMut(&usvg::Node),
|
||||
F: FnMut(&mut usvg::Node),
|
||||
{
|
||||
for descendant in node.descendants() {
|
||||
f(&descendant);
|
||||
descendant.subroots(|subroot| traverse_svg(&subroot, f))
|
||||
f(node);
|
||||
|
||||
node.subroots_mut(|subroot| {
|
||||
for child in &mut subroot.children {
|
||||
traverse_svg(child, f);
|
||||
}
|
||||
});
|
||||
|
||||
if let Node::Group(ref mut group) = node {
|
||||
for child in &mut group.children {
|
||||
traverse_svg(child, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user