Skip to content

boolean-maybe/go-resvg

Repository files navigation

go-resvg

Pure-Go SVG rendering via resvg compiled to WASM and run with wazero. No CGo, no external binaries at go get / go build time.

Install

go get github.com/boolean-maybe/go-resvg

Usage

r, err := resvg.New()
if err != nil {
    log.Fatal(err)
}
defer r.Close()

png, err := r.RenderPNG(svgBytes, resvg.RenderOptions{Width: 800, Height: 600})

Render returns an image.Image (*image.RGBA); RenderPNG returns encoded PNG bytes. Setting only Width or only Height derives the other from the SVG's intrinsic aspect ratio; setting both renders at exactly those dimensions; setting neither uses the intrinsic size. Create one Renderer and reuse it; it pools wasm instances internally and is safe for concurrent use.

Invalid input returns ErrInvalidSVG; a rasterization failure returns ErrRenderFailed — both matchable with errors.Is.

Fonts

DejaVu Sans (Regular / Bold / Oblique / BoldOblique, subsetted to common Latin/Cyrillic/Greek/punctuation ranges) is embedded and registered as the sans-serif family. Text renders when the SVG:

  • names a generic family (sans-serif, etc.), or
  • omits font-family (the default family is DejaVu Sans), or
  • names DejaVu Sans explicitly.

An explicitly named family that is not embedded (e.g. font-family="Helvetica Neue") is not silently substituted — resvg drops that text run. Author SVGs against the embedded family or a generic name.

Building resvg.wasm from source

The committed resvg.wasm is go:embed-ed, so consumers never need a Rust toolchain. To rebuild it you need Rust + the wasm32-wasip1 target, binaryen (wasm-opt), and fonttools (pyftsubset):

# subset DejaVu into rust/fonts/ (override FONT_SRC / PYFTSUBSET for your system)
make fonts FONT_SRC=/path/to/dejavu PYFTSUBSET=/path/to/pyftsubset

# cargo build + wasm-opt -> resvg.wasm
make wasm

rust/fonts/*.ttf are committed, so a plain make wasm rebuilds the artifact without re-subsetting.

Or reproducibly via the pinned toolchain (requires Docker):

make wasm-docker

The committed resvg.wasm is the output of make wasm-docker (pinned Rust + binaryen). A local make wasm with a different rustc / wasm-opt version produces a functionally identical but not byte-identical artifact — the WASM ABI is stable, but codegen and optimizer output vary across toolchain versions and host architectures. Rebuild with make wasm-docker to reproduce the committed bytes.

WASM ABI

The Rust crate exports a minimal C-ABI over resvg:

  • wasm_alloc(len) -> ptr / wasm_free(ptr, len) — linear-memory allocation (named wasm_* to avoid a duplicate-symbol clash with the wasi libc free).
  • render(svg_ptr, svg_len, width, height) -> header_ptr — returns a pointer to a 20-byte little-endian result header: [status i32, width u32, height u32, data_ptr u32, data_len u32]. status == 0 is success with data_ptr/data_len pointing at width*height*4 RGBA bytes; 1 = invalid SVG; 2 = render failure.

About

No description, website, or topics provided.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors