Help us shape the future of Go! Take the 2026 Go Developer Survey

svg

package module
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 10, 2026 License: BSD-3-Clause Imports: 6 Imported by: 0

README

go-widgets/svg

CI release pkg.go.dev coverage gallery license

Snapshot: turn any RGBA byte buffer (the output of a go-widgets/toolkit widget composition, or any other pixel producer) into a portable, self-contained SVG document.

Pure Go, stdlib only, BSD-3-Clause. 100% statement coverage.

Why

Widgets in go-widgets/toolkit are pixel-blitting by design — every Draw call writes bytes into a []byte at (x, y). That is great for rendering, less great for embedding a screenshot in a README: raw PNGs travel poorly across dark-mode readers, don't scale on Retina displays, and lose their crispness at any zoom level.

svg.Snapshot wraps the render in an SVG envelope. The SVG declares a viewBox pinned to the render's pixel dimensions and carries the pixels as a base-64 PNG under image-rendering: pixelated. The result:

  • Bit-exact: every pixel you see in the browser is the same pixel the widget produced. No re-vectorisation, no font substitution, no antialiasing drift.
  • Scales crisply: any zoom keeps hard edges (pixelated hint). Perfect for a docs site that hosts one asset but serves it at multiple sizes.
  • Self-contained: one file, zero external assets. Drops into any Markdown renderer that already accepts SVG images (GitHub, GitLab, mkdocs, Hugo, ...).

Use

The root package works against any RGBA byte producer:

import (
    "os"
    "github.com/go-widgets/svg"
)

surface := make([]byte, 4*w*h)  // fill with anything
// ...your draw code here...

f, _ := os.Create("out.svg")
defer f.Close()
svg.Snapshot(f, surface, w, h, "my image")

For go-widgets/toolkit widgets specifically, the sibling widget subpackage removes the manual make + Draw + Snapshot dance:

import (
    "os"
    "github.com/go-widgets/svg/widget"
    "github.com/go-widgets/toolkit"
)

btn := toolkit.NewButton("Click me", nil)
btn.SetBounds(toolkit.Rect{X: 0, Y: 0, W: 200, H: 40})

f, _ := os.Create("button.svg")
defer f.Close()
widget.Snapshot(f, btn, 200, 40, toolkit.DefaultLight(), "widget: button")

// Or a raw PNG (no SVG envelope):
p, _ := os.Create("button.png")
defer p.Close()
widget.PNG(p, btn, 200, 40, toolkit.DefaultLight())

The label argument on Snapshot becomes the SVG's <title> + aria-label for a11y + previewer tooltips. Pass "" to omit.

API

Root package (svg):

func Snapshot(w io.Writer, surface []byte, width, height int, label string) (int, error)
  • Returns the byte count written + the first error, mirroring io.Writer.
  • Errors on dimension ≤ 0 or len(surface) != 4*width*height.
  • Errors bubble up from w.Write calls (header, title, body).
  • All XML output escapes the five predefined XML entities in label (both inside <title> and in the aria-label attribute), so a label containing <b>&"'</b> remains valid XML.

Widget subpackage (svg/widget):

func Snapshot(w io.Writer, wg toolkit.Widget, width, height int, theme *toolkit.Theme, label string) (int, error)
func PNG(w io.Writer, wg toolkit.Widget, width, height int, theme *toolkit.Theme) (int, error)
  • Renders wg into a fresh width×height RGBA surface via wg.Draw(painter.NewPixelPainter(surface, width, height), theme), then serialises. Snapshot wraps in an SVG envelope; PNG emits raw PNG bytes.
  • Errors on non-positive dimensions, nil widget, nil theme.
  • Split into a subpackage so the root svg stays dep-free — a consumer that only uses svg.Snapshot([]byte) for a home-grown pixel producer does not pull go-widgets/toolkit into its module graph.

License

BSD-3-Clause.

Documentation

Overview

Package svg turns a rendered RGBA byte buffer (the output of any go-widgets/toolkit widget composition) into a portable SVG document that embeds the pixels as a base64-encoded PNG. The wrapper scales crisply at any zoom level and travels well in READMEs, GitHub issues, docs sites, tweet threads and PDF exports.

Why not a "true" vector renderer? Widgets in go-widgets/toolkit are pixel-blitting by design — every draw call writes bytes into a []byte at (x, y). Converting that pipeline to <rect>/<text>/etc. would either double every widget's implementation or lose the exact alignment users see in-browser. Embedding the render as PNG is bit-exact (any pixel you see in the browser is the same pixel in the SVG) while still giving you the "scales to any DPI" benefit + the "one file, no external assets" portability.

Typical use in a doc-generation script:

surface := make([]byte, 4*w*h)
btn := toolkit.NewButton("Click me", nil)
btn.SetBounds(toolkit.Rect{X: 0, Y: 0, W: w, H: h})
btn.Draw(painter.NewPixelPainter(surface, w, h), toolkit.DefaultLight())
f, _ := os.Create("button.svg")
svg.Snapshot(f, surface, w, h, "widget: button")

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Snapshot

func Snapshot(w io.Writer, surface []byte, width, height int, label string) (int, error)

Snapshot writes an SVG document that wraps the RGBA pixels of a widget render. width + height are the buffer's dimensions; label is a short human-readable string embedded as the SVG's <title>/<desc> for a11y + previewer tooltips (pass "" to omit).

The output is a single, self-contained SVG (no external assets) with a <image> child pointing at data:image/png;base64,… so it pastes cleanly into any Markdown renderer that already accepts SVG images (GitHub, GitLab, mkdocs, Hugo, ...).

Returns the number of bytes written + the first error, mirroring the io.Writer convention.

Types

This section is empty.

Directories

Path Synopsis
cmd
gallery-render command
Command gallery-render writes an SVG + PNG snapshot of every go-widgets/toolkit widget kind to a directory.
Command gallery-render writes an SVG + PNG snapshot of every go-widgets/toolkit widget kind to a directory.
Package widget wraps the go-widgets/toolkit `Widget` interface with two write-to-io.Writer conveniences:
Package widget wraps the go-widgets/toolkit `Widget` interface with two write-to-io.Writer conveniences:

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL