Skip to content
Resources and images

Resources and images

A resource is a named block of bytes, such as an image, an icon or a font. Anything in Bellui that shows an image takes a bellui.Resource: canvas.NewImageFromResource, widget.NewIcon, widget.NewButtonWithIcon, App.SetIcon and more. The interface has two methods, Name() and Content(). The name identifies the resource, and its extension tells Bellui the format, so an SVG file’s name should end in .svg.

Embed files in your binary

Go’s embed package puts a file into the compiled program. bellui.NewStaticResource turns the bytes into a resource:

//go:embed logo.svg
var logoSVG []byte

// The name identifies the resource; keep the file extension, so an SVG
// is recognised as one.
var logo = bellui.NewStaticResource("logo.svg", logoSVG)

The file logo.svg sits next to main.go. Embedded resources need no file at run time, so this works the same on desktop, mobile and web.

Once you have a resource, use it wherever an image is wanted:

// One resource, used three ways.
a.SetIcon(logo) // the app icon, and the default icon of new windows

embedded := canvas.NewImageFromResource(logo)
embedded.FillMode = canvas.ImageFillContain

button := widget.NewButtonWithIcon("Logo", logo, func() {})

Theme icons

The theme package has a function for each standard icon: theme.HomeIcon(), theme.SettingsIcon(), theme.SearchIcon(), theme.DeleteIcon(), theme.InfoIcon() and many more. theme.Icon(name) looks one up by its theme.IconName... constant. The standard icons take their colour from the current theme, so they look right in light and dark mode.

To give your own single-colour SVG the same behaviour, wrap it. theme.NewThemedResource uses the foreground colour; theme.NewPrimaryThemedResource, NewErrorThemedResource, NewWarningThemedResource and NewSuccessThemedResource use those colours. theme.NewColoredResource(res, name) takes any theme colour name.

// Theme icons follow the current theme's colours and switch with it.
home := widget.NewIcon(theme.HomeIcon())

// Wrap your own monochrome icon to give it the theme's primary colour.
tinted := widget.NewIcon(theme.NewPrimaryThemedResource(logo))

Load images at run time

When the image is not known at build time, load it:

FunctionSource
canvas.NewImageFromFile(path)A file path
canvas.NewImageFromURI(uri)A bellui.URI: a file, or another scheme such as https
canvas.NewImageFromReader(r, name)Any io.Reader; the name identifies it and gives its format
canvas.NewImageFromImage(img)A Go image.Image you already have
if len(os.Args) > 1 {
	// A file:// URI is read straight from disk.
	fromDisk := canvas.NewImageFromURI(storage.NewFileURI(os.Args[1]))
	fromDisk.FillMode = canvas.ImageFillContain
	items = append(items, fromDisk)
}

storage.NewFileURI makes a URI from a path. For a file URI, NewImageFromURI is the same as NewImageFromFile with that path.

For any scheme other than file, NewImageFromURI downloads the data before it returns. Do not call it with a network URI from a callback, or the window freezes until the download ends. Load it on a goroutine and set the image with bellui.Do.

To make a resource rather than an image:

The whole example

// Images from three sources: a file embedded in the binary, the theme's
// icon set, and a file on disk named on the command line.
package main

import (
	_ "embed"
	"os"

	"github.com/belluikit/bellui"
	"github.com/belluikit/bellui/app"
	"github.com/belluikit/bellui/canvas"
	"github.com/belluikit/bellui/container"
	"github.com/belluikit/bellui/core"
	"github.com/belluikit/bellui/geo"
	"github.com/belluikit/bellui/storage"
	"github.com/belluikit/bellui/theme"
	"github.com/belluikit/bellui/widget"
)

//go:embed logo.svg
var logoSVG []byte

// The name identifies the resource; keep the file extension, so an SVG
// is recognised as one.
var logo = bellui.NewStaticResource("logo.svg", logoSVG)


func main() {
	a := app.NewWithID("com.example.resources")
	w := a.NewWindow("Resources")

	// One resource, used three ways.
	a.SetIcon(logo) // the app icon, and the default icon of new windows

	embedded := canvas.NewImageFromResource(logo)
	embedded.FillMode = canvas.ImageFillContain

	button := widget.NewButtonWithIcon("Logo", logo, func() {})

	// Theme icons follow the current theme's colours and switch with it.
	home := widget.NewIcon(theme.HomeIcon())

	// Wrap your own monochrome icon to give it the theme's primary colour.
	tinted := widget.NewIcon(theme.NewPrimaryThemedResource(logo))

	items := []core.CanvasObject{embedded, button, home, tinted}

	if len(os.Args) > 1 {
		// A file:// URI is read straight from disk.
		fromDisk := canvas.NewImageFromURI(storage.NewFileURI(os.Args[1]))
		fromDisk.FillMode = canvas.ImageFillContain
		items = append(items, fromDisk)
	}

	w.SetContent(container.NewGridWrap(geo.NewSize(96, 96), items...))
	w.Resize(geo.NewSize(480, 240))
	bellui.ShowAndRun(w)
}

Run it with an image path to also show an image loaded from disk:

go run . ~/Pictures/photo.png