offscreen/renderer.go
Functions
func Image
func (r *Renderer) Image() *image.RGBA {
return r.img
}
func NewRenderer
NewRenderer creates an offscreen renderer with the given pixel dimensions.
Width and height must be positive; they are clamped to a minimum of 1.
By default, a Material 3 light theme is applied and the background is
transparent. Override with [WithTheme], [WithBackground], and [WithScale].
func NewRenderer(width, height int, opts ...Option) *Renderer {
if width < 1 {
width = 1
}
if height < 1 {
height = 1
}
r := &Renderer{
width: width,
height: height,
scale: 1.0,
theme: material3.New(m3DefaultSeed),
background: widget.ColorTransparent,
}
for _, opt := range opts {
opt(r)
}
return r
}
func Render
Render lays out and draws the widget into the offscreen buffer.
In default mode, the widget receives the renderer dimensions as loose
constraints. In fit-to-content mode ([WithFitSize]), the widget is
measured first to determine its preferred size, then the canvas is
allocated at that size. Calling Render again replaces the previous image.
func (r *Renderer) Render(w widget.Widget) {
ctx := widget.NewContext()
ctx.SetThemeProvider(r.theme)
ctx.SetScale(r.scale)
width, height := r.width, r.height
if r.fitSize {
width, height = r.measure(w, ctx)
}
if width < 1 {
width = 1
}
if height < 1 {
height = 1
}
ctx.SetWindowSize(geometry.Sz(float32(width), float32(height)))
constraints := geometry.Loose(geometry.Sz(float32(width), float32(height)))
w.Layout(ctx, constraints)
dc := gg.NewContext(width, height)
canvas := render.NewCanvas(dc, width, height)
canvas.Clear(r.background)
widget.DrawTree(w, ctx, canvas)
r.img = internalRender.ToRGBA(dc.Image())
_ = dc.Close()
}
func WithBackground
WithBackground sets the canvas clear color before drawing.
The default is transparent (zero alpha).
func WithBackground(c widget.Color) Option {
return func(r *Renderer) {
r.background = c
}
}
func WithFitSize
WithFitSize enables measure-then-render mode. The renderer measures the
widget's preferred size before allocating the canvas, so the caller does
not need to know dimensions upfront. Pass width=0, height=0 to NewRenderer.
This follows the universal enterprise pattern (Flutter IntrinsicWidth,
Qt6 sizeHint, SwiftUI sizeThatFits, Compose SubcomposeLayout).
Use [WithMaxSize] to constrain expansion for widgets that grow unbounded.
func WithFitSize() Option {
return func(r *Renderer) {
r.fitSize = true
}
}
func WithMaxSize
WithMaxSize sets maximum dimensions for fit-to-content mode.
A value of 0 means unlimited in that axis.
Only effective when [WithFitSize] is also set.
func WithMaxSize(width, height int) Option {
return func(r *Renderer) {
r.maxWidth = width
r.maxHeight = height
}
}
func WithScale
WithScale sets the display scale factor for HiDPI rendering.
The default is 1.0. A value of 2.0 renders at Retina density.
func WithScale(s float32) Option {
return func(r *Renderer) {
if s > 0 {
r.scale = s
}
}
}
func WithTheme
WithTheme overrides the default Material 3 light theme.
func WithTheme(tp widget.ThemeProvider) Option {
return func(r *Renderer) {
r.theme = tp
}
}
Structs
type Renderer struct
Renderer renders a widget tree into an offscreen image.
Create with [NewRenderer]. Configure with [Option] functions.
Call [Renderer.Render] to draw a widget, then [Renderer.Image] to
retrieve the result.
type Renderer struct {
width int
height int
scale float32
theme widget.ThemeProvider
background widget.Color
img *image.RGBA
fitSize bool
maxWidth int
maxHeight int
}
Image returns the rendered image, or nil if [Render] has not been called.