svg
Turn SVG documents into images, read their size and viewBox without drawing them, and register fonts for SVG text.
import "std:svg"std:svg renders an SVG document into an *img.Image, so vector artwork (icons, logos, charts) can be scaled to any size and then saved, drawn or shown like any other image. It also reads a document's size without drawing it.
Reach for it when you have SVG text or files and need pixels: thumbnails, icons at several sizes, or a chart a server draws as PNG.
Rendering#
svg.render(text) returns a result holding an image of the document's own size:
import "std:svg"
string doc = `<svg xmlns="http://www.w3.org/2000/svg" width="100" height="50" viewBox="0 0 200 100">
<rect width="200" height="100" fill="white"/>
<circle cx="50" cy="50" r="30" fill="#ff0000"/>
</svg>`
auto pic = svg.render(doc).unwrap()
log pic.width() pic.height()
log pic.pixel(25, 25)
log pic.pixel(90, 40)The document says width="100" and a viewBox twice as large, so the image is 100 by 50 and the drawing is scaled to fit. The circle is red where the pixel is inside it, and white elsewhere. Where nothing is drawn, the image is transparent.
Choosing a size#
Vector art stays sharp at any size, so ask for the size you want. scale multiplies the document's size. width or height alone keep the aspect ratio, and both stretch the drawing to fit:
import "std:svg"
string doc = [
`<svg xmlns="http://www.w3.org/2000/svg" width="100" height="50">`,
`<rect width="100" height="50" fill="blue"/>`,
`</svg>`
].join("")
auto twice = svg.render(doc, {scale: 2}).unwrap()
log twice.width() twice.height()
auto narrow = svg.render(doc, {width: 40}).unwrap()
log narrow.width() narrow.height()
auto exact = svg.render(doc, {width: 30, height: 30}).unwrap()
log exact.width() exact.height()Giving scale together with width or height throws a ValueError, since they would contradict each other.
Reading the size without rendering#
svg.info(text) resolves the width and height a browser would give the document, and its viewBox (or null when it has none). It is cheap, so use it to decide whether to render at all:
import "std:svg"
string doc = [
`<svg xmlns="http://www.w3.org/2000/svg" `,
`width="100" height="50" viewBox="0 0 200 100"/>`
].join("")
auto info = svg.info(doc).unwrap()
log info.width info.height
log info.viewBox
string plain = `<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10"/>`
log svg.info(plain).unwrap().viewBoxFrom files, and when it fails#
Every function has a File version that takes a path: svg.renderFile, svg.infoFile. All of them return results. Text that is not an SVG is a ParseError, and a missing file is a NotFoundError:
import "std:svg"
import "std:fs"
string source = [
`<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10">`,
`<rect width="10" height="10" fill="blue"/>`,
`</svg>`
].join("")
fs.writeFile("icon.svg", source).unwrap()
auto icon = svg.renderFile("icon.svg", {scale: 3}).unwrap()
log icon.width() icon.pixel(30, 30)
log svg.render("<html>").unwrapErr().kind
log svg.renderFile("missing.svg").unwrapErr().kind
fs.remove("icon.svg").unwrap()Saving the result#
The image is an ordinary *img.Image, so use its methods to save or change it:
import "std:svg"
import "std:img"
import "std:fs"
fs.remove("logo.png", {force: true}).unwrap()
string doc = [
`<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64">`,
`<circle cx="32" cy="32" r="30" fill="orange"/>`,
`</svg>`
].join("")
auto logo = svg.render(doc, {scale: 2}).unwrap()
logo.save("logo.png").unwrap()
auto info = img.infoFile("logo.png").unwrap()
log info.width info.height info.format
fs.remove("logo.png").unwrap()Fonts#
SVG text draws with a default font. To use a font from a file, register it first under the family name the SVG asks for with svg.addFont(family, path). It returns a result, and fails with ParseError if the file is not a font:
import "std:svg"
svg.addFont("Inter", "fonts/Inter.ttf").unwrap()
string doc = [
`<svg xmlns="http://www.w3.org/2000/svg" width="200" height="40">`,
`<text x="4" y="28" font-family="Inter" font-size="24">Hello</text>`,
`</svg>`
].join("")
auto pic = svg.render(doc).unwrap()
pic.save("hello.png").unwrap()An SVG says width="100" height="50". You call svg.render(doc, {scale: 3}). How big is the image?
An icon at two sizes
Render the same 16 by 16 SVG at 16 and at 64 pixels wide, and print both widths.
16 64
API reference#
7 members, generated from the std:svg source of OSL 9.3.0.
Functions
svg.addFont(string family, string path) result<unit, error>addFont registers the TTF or OTF font file at path as family, so SVG text in that family renders with it wherever SVGs are drawn (such as raylib.loadSVG). Fails with NotFoundError, PermissionError or IOError when the file can't be read, and ParseError when it isn't a font.
svg.info(string text) result<{height: number, viewBox: {height: number, width: number, x: number, y: number}?, width: number}, error>info reads an SVG document's intrinsic size and viewBox without rendering it. The record's keys: width and height, the size in CSS pixels that a browser gives the image, resolved from the root's width, height and viewBox; and viewBox, the root's {x, y, width, height} in user units, or null when it has none. Fails with ParseError when text isn't an SVG document.
svg.infoFile(string path) result<{height: number, viewBox: {height: number, width: number, x: number, y: number}?, width: number}, error>infoFile reads the size and viewBox of the SVG file at path, as svg.info does. Fails with NotFoundError, PermissionError or IOError when the file can't be read, and ParseError when it isn't an SVG document.
svg.render(string text, object? options) result<*img.Image, error>render draws SVG text into a new img.Image, transparent where the drawing is. By default the image is the document's intrinsic size in CSS pixels (as svg.info reports it), rounded up. Options: scale (multiplies that size, default 1), or width and height in pixels (give one to keep the aspect ratio, or both to stretch the drawing to exactly that size). Fails with ParseError when text isn't an SVG document or has no size, and ValueError when the image would be over 100000 pixels a side or 100 megapixels; throws ValueError for an option that isn't more than 0, or scale given with width or height.
svg.renderFile(string path, object? options) result<*img.Image, error>renderFile draws the SVG file at path into a new img.Image, as svg.render does. Fails with NotFoundError, PermissionError or IOError when the file can't be read, and otherwise as svg.render.
svg.size(string path) number[]Deprecated. Deprecated: use svg.infoFile(path) instead, which reports failures.
size returns an SVG file's intrinsic [width, height], or [0, 0] if it can't be read.
svg.viewBox(string path) number[]Deprecated. Deprecated: use svg.infoFile(path).viewBox instead.
viewBox returns the root element's viewBox as [x, y, width, height], or [0, 0, width, height] from the width and height attributes without one.