summaryrefslogtreecommitdiff
path: root/crates/typst-library/src/visualize
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2025-02-17 11:56:00 +0100
committerGitHub <noreply@github.com>2025-02-17 10:56:00 +0000
commit25c86accbb4adc0e7542d2c5957dff6e939cbf48 (patch)
tree8db19e48038ffe1eeee1232dc54ec242ce48e029 /crates/typst-library/src/visualize
parent5fc679f3e7501ee5831f1b4b7789350f43b4c221 (diff)
More robust SVG auto-detection (#5878)
Diffstat (limited to 'crates/typst-library/src/visualize')
-rw-r--r--crates/typst-library/src/visualize/image/mod.rs18
1 files changed, 16 insertions, 2 deletions
diff --git a/crates/typst-library/src/visualize/image/mod.rs b/crates/typst-library/src/visualize/image/mod.rs
index 97189e22..258eb96f 100644
--- a/crates/typst-library/src/visualize/image/mod.rs
+++ b/crates/typst-library/src/visualize/image/mod.rs
@@ -398,8 +398,7 @@ impl ImageFormat {
return Some(Self::Raster(RasterFormat::Exchange(format)));
}
- // SVG or compressed SVG.
- if data.starts_with(b"<svg") || data.starts_with(&[0x1f, 0x8b]) {
+ if is_svg(data) {
return Some(Self::Vector(VectorFormat::Svg));
}
@@ -407,6 +406,21 @@ impl ImageFormat {
}
}
+/// Checks whether the data looks like an SVG or a compressed SVG.
+fn is_svg(data: &[u8]) -> bool {
+ // Check for the gzip magic bytes. This check is perhaps a bit too
+ // permissive as other formats than SVGZ could use gzip.
+ if data.starts_with(&[0x1f, 0x8b]) {
+ return true;
+ }
+
+ // If the first 2048 bytes contain the SVG namespace declaration, we assume
+ // that it's an SVG. Note that, if the SVG does not contain a namespace
+ // declaration, usvg will reject it.
+ let head = &data[..data.len().min(2048)];
+ memchr::memmem::find(head, b"http://www.w3.org/2000/svg").is_some()
+}
+
/// A vector graphics format.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)]
pub enum VectorFormat {