Read images inside SVGs only from data: URLs

This commit is contained in:
aiongg
2026-10-16 17:05:09 +00:00
parent 248e10908b
commit 8c3bbdc09f
+38 -1
View File
@@ -72,7 +72,11 @@ fn svg_options() -> &'static usvg::Options<'static> {
db.set_sans_serif_family("Source Sans 3");
db.set_monospace_family("JetBrains Mono");
let font_resolver = usvg::FontResolver { select_font: select_font(), select_fallback: select_fallback() };
usvg::Options { fontdb: Arc::new(db), font_family: "Source Sans 3".into(), font_resolver, ..Default::default() }
// Images inside an SVG come only from `data:` URLs: an `href` naming a file is not read
// (it is left out, as usvg leaves out an image it can't load).
let image_href_resolver =
usvg::ImageHrefResolver { resolve_data: usvg::ImageHrefResolver::default_data_resolver(), resolve_string: Box::new(|_, _| None) };
usvg::Options { fontdb: Arc::new(db), font_family: "Source Sans 3".into(), font_resolver, image_href_resolver, ..Default::default() }
})
}
@@ -510,6 +514,39 @@ mod tests {
assert!(!is_svg(b"\x89PNG"));
}
#[test]
fn svg_images_come_only_from_data_urls() {
let dir = std::env::temp_dir().join(format!("dc-svg-href-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let file = dir.join("red.png");
image::RgbaImage::from_pixel(4, 4, image::Rgba([255, 0, 0, 255])).save(&file).unwrap();
let blue = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10'%3E%3Crect width='10' height='10' fill='blue'/%3E%3C/svg%3E";
let svg = format!(
r#"<svg xmlns="http://www.w3.org/2000/svg" width="30" height="10">
<image x="0" y="0" width="10" height="10" href="{}"/>
<image x="10" y="0" width="10" height="10" href="{blue}"/>
<image x="20" y="0" width="10" height="10" href="/etc/hostname"/>
</svg>"#,
file.display()
);
// The image nodes usvg kept: only the data URL's (PDF export embeds every one).
fn images(g: &usvg::Group) -> usize {
g.children()
.iter()
.map(|n| match n {
usvg::Node::Group(g) => images(g),
usvg::Node::Image(_) => 1,
_ => 0,
})
.sum()
}
assert_eq!(images(svg_tree(svg.as_bytes()).unwrap().root()), 1, "files the SVG names are not read");
let (px, w, _) = render_svg(svg.as_bytes(), 30).unwrap();
let at = |x: usize, y: usize| px[(y * w as usize + x) * 4..][..4].to_vec();
assert_eq!(at(15, 5), [0, 0, 255, 255], "a data URL is drawn");
let _ = std::fs::remove_dir_all(&dir);
}
/// The family of the font that sets each text glyph of `svg`, and the glyph's id.
fn glyph_families(svg: &str) -> Vec<(String, u16)> {
fn walk(g: &usvg::Group, tree: &usvg::Tree, out: &mut Vec<(String, u16)>) {