mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
More robust SVG auto-detection (#5878)
This commit is contained in:
parent
5fc679f3e7
commit
25c86accbb
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2966,6 +2966,7 @@ dependencies = [
|
|||||||
"kamadak-exif",
|
"kamadak-exif",
|
||||||
"kurbo",
|
"kurbo",
|
||||||
"lipsum",
|
"lipsum",
|
||||||
|
"memchr",
|
||||||
"palette",
|
"palette",
|
||||||
"phf",
|
"phf",
|
||||||
"png",
|
"png",
|
||||||
|
@ -73,6 +73,7 @@ kamadak-exif = "0.6"
|
|||||||
kurbo = "0.11"
|
kurbo = "0.11"
|
||||||
libfuzzer-sys = "0.4"
|
libfuzzer-sys = "0.4"
|
||||||
lipsum = "0.9"
|
lipsum = "0.9"
|
||||||
|
memchr = "2"
|
||||||
miniz_oxide = "0.8"
|
miniz_oxide = "0.8"
|
||||||
native-tls = "0.2"
|
native-tls = "0.2"
|
||||||
notify = "8"
|
notify = "8"
|
||||||
|
@ -38,6 +38,7 @@ indexmap = { workspace = true }
|
|||||||
kamadak-exif = { workspace = true }
|
kamadak-exif = { workspace = true }
|
||||||
kurbo = { workspace = true }
|
kurbo = { workspace = true }
|
||||||
lipsum = { workspace = true }
|
lipsum = { workspace = true }
|
||||||
|
memchr = { workspace = true }
|
||||||
palette = { workspace = true }
|
palette = { workspace = true }
|
||||||
phf = { workspace = true }
|
phf = { workspace = true }
|
||||||
png = { workspace = true }
|
png = { workspace = true }
|
||||||
|
@ -398,8 +398,7 @@ impl ImageFormat {
|
|||||||
return Some(Self::Raster(RasterFormat::Exchange(format)));
|
return Some(Self::Raster(RasterFormat::Exchange(format)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// SVG or compressed SVG.
|
if is_svg(data) {
|
||||||
if data.starts_with(b"<svg") || data.starts_with(&[0x1f, 0x8b]) {
|
|
||||||
return Some(Self::Vector(VectorFormat::Svg));
|
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.
|
/// A vector graphics format.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)]
|
||||||
pub enum VectorFormat {
|
pub enum VectorFormat {
|
||||||
|
@ -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 interaction of clipping and outset on [`box`] and [`block`]
|
||||||
- Fixed panic with [`path`] of infinite length
|
- Fixed panic with [`path`] of infinite length
|
||||||
- Fixed non-solid (e.g. tiling) text fills in clipped blocks
|
- 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
|
- Auto-detection of image formats from a raw buffer now has support for SVGs
|
||||||
SVGs
|
|
||||||
|
|
||||||
## Scripting
|
## Scripting
|
||||||
- Functions that accept [file paths]($syntax/#paths) now also accept raw
|
- Functions that accept [file paths]($syntax/#paths) now also accept raw
|
||||||
|
BIN
tests/ref/image-svg-auto-detection.png
Normal file
BIN
tests/ref/image-svg-auto-detection.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 129 B |
@ -65,6 +65,17 @@ A #box(image("/assets/images/tiger.jpg", height: 1cm, width: 80%)) B
|
|||||||
caption: [Bilingual text]
|
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-pixmap-rgb8 ---
|
||||||
#image(
|
#image(
|
||||||
bytes((
|
bytes((
|
||||||
@ -152,8 +163,8 @@ A #box(image("/assets/images/tiger.jpg", height: 1cm, width: 80%)) B
|
|||||||
#image("path/does/not/exist")
|
#image("path/does/not/exist")
|
||||||
|
|
||||||
--- image-bad-format ---
|
--- image-bad-format ---
|
||||||
// Error: 2-22 unknown image format
|
// Error: 2-37 unknown image format
|
||||||
#image("./image.typ")
|
#image("/assets/plugins/hello.wasm")
|
||||||
|
|
||||||
--- image-bad-svg ---
|
--- image-bad-svg ---
|
||||||
// Error: 2-33 failed to parse SVG (found closing tag 'g' instead of 'style' in line 4)
|
// Error: 2-33 failed to parse SVG (found closing tag 'g' instead of 'style' in line 4)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user