More robust SVG auto-detection (#5878)

This commit is contained in:
Laurenz 2025-02-17 11:56:00 +01:00
parent e294fe85a5
commit d48708c5d5
7 changed files with 33 additions and 6 deletions

1
Cargo.lock generated
View File

@ -2966,6 +2966,7 @@ dependencies = [
"kamadak-exif",
"kurbo",
"lipsum",
"memchr",
"palette",
"phf",
"png",

View File

@ -73,6 +73,7 @@ kamadak-exif = "0.6"
kurbo = "0.11"
libfuzzer-sys = "0.4"
lipsum = "0.9"
memchr = "2"
miniz_oxide = "0.8"
native-tls = "0.2"
notify = "8"

View File

@ -38,6 +38,7 @@ indexmap = { workspace = true }
kamadak-exif = { workspace = true }
kurbo = { workspace = true }
lipsum = { workspace = true }
memchr = { workspace = true }
palette = { workspace = true }
phf = { workspace = true }
png = { workspace = true }

View File

@ -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 {

View File

@ -99,8 +99,7 @@ description: Changes slated to appear in Typst 0.13.0
- Fixed interaction of clipping and outset on [`box`] and [`block`]
- Fixed panic with [`path`] of infinite length
- Fixed non-solid (e.g. tiling) text fills in clipped blocks
- Auto-detection of image formats from a raw buffer now has basic support for
SVGs
- Auto-detection of image formats from a raw buffer now has support for SVGs
## Scripting
- Functions that accept [file paths]($syntax/#paths) now also accept raw

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

View File

@ -65,6 +65,17 @@ A #box(image("/assets/images/tiger.jpg", height: 1cm, width: 80%)) B
caption: [Bilingual text]
)
--- image-svg-auto-detection ---
#image(bytes(
```
<?xml version="1.0" encoding="utf-8"?>
<!-- An SVG -->
<svg width="200" height="150" xmlns="http://www.w3.org/2000/svg">
<rect fill="red" stroke="black" x="25" y="25" width="150" height="100"/>
</svg>
```.text
))
--- image-pixmap-rgb8 ---
#image(
bytes((
@ -152,8 +163,8 @@ A #box(image("/assets/images/tiger.jpg", height: 1cm, width: 80%)) B
#image("path/does/not/exist")
--- image-bad-format ---
// Error: 2-22 unknown image format
#image("./image.typ")
// Error: 2-37 unknown image format
#image("/assets/plugins/hello.wasm")
--- image-bad-svg ---
// Error: 2-33 failed to parse SVG (found closing tag 'g' instead of 'style' in line 4)