Support SVG sources (closes #68)
check / check (push) Canceled after 0s

The fetcher accepts image/svg+xml and internal/magic detects SVG. orig
of an SVG at the orig size is the SVG unchanged, cached as a variant; at
another size it is ErrSVGNotOriginalSize (400). Any other format renders
it with libvips' thumbnail at the least size covering the output, at
most 8192 on a side, so it stays sharp. An SVG's own size is not
limited; one with a side over 8192 times the other is ErrSVGTooThin
(415). The cache reads up to 1024 first bytes to find a file's format.
Tests that pinned the SVG refusal now expect SVG to be read. Render time
and memory are unbounded: P1 in TODO.md until the owner decides on
#68.

Model: opus-5-5
This commit is contained in:
clawbot committed 2026-11-11 15:43:16 +00:00
1 parent 7f87aa17ca
commit d96899eca6
20 files changed
+858 -87

No files matched your search

+27 -1
View File
@@ -20,6 +20,10 @@ var (
// MinMagicBytes is the minimum number of bytes needed to detect format.
const MinMagicBytes = 12
// MaxMagicBytes is the most bytes DetectFormat looks at. An SVG's root
// element must start within them, as libvips requires.
const MaxMagicBytes = 1024
// Magic byte signatures for supported formats.
// These are effectively constants but Go doesn't support const slices.
//
@@ -39,6 +43,12 @@ var (
}
)
// utf8BOM is the UTF-8 byte order mark, which a text file such as an SVG may
// start with.
//
//nolint:gochecknoglobals // immutable lookup data
var utf8BOM = []byte{0xEF, 0xBB, 0xBF}
// WebP identifier appears at offset 8 after RIFF header.
//
//nolint:gochecknoglobals // immutable lookup data
@@ -53,7 +63,7 @@ var (
)
// DetectFormat detects the image format from magic bytes. Data in none of
// the formats pixa reads, SVG included, is ErrUnknownFormat.
// the formats pixa reads is ErrUnknownFormat.
func DetectFormat(data []byte) (imagerequest.Format, error) {
if len(data) < MinMagicBytes {
return "", ErrNotEnoughData
@@ -96,9 +106,25 @@ func DetectFormat(data []byte) (imagerequest.Format, error) {
return imagerequest.FormatJXL, nil
}
if isSVG(data) {
return imagerequest.FormatSVG, nil
}
return "", ErrUnknownFormat
}
// isSVG reports whether data starts as an SVG does: with a "<", after an
// optional UTF-8 byte order mark and white space, and with "<svg" within the
// first MaxMagicBytes bytes. Before the root element an SVG may have an XML
// declaration, comments and a DOCTYPE.
func isSVG(data []byte) bool {
data = data[:min(len(data), MaxMagicBytes)]
text := bytes.TrimLeft(bytes.TrimPrefix(data, utf8BOM), " \t\r\n")
return bytes.HasPrefix(text, []byte("<")) &&
bytes.Contains(text, []byte("<svg"))
}
// ValidateMagicBytes detects the format of data from its magic bytes, and
// returns it when it is the format the declared MIME type names. Data in
// another format is ErrMagicByteMismatch.