Skip to content

Image

An image shows one picture, such as a photo, a cover or a profile picture. Use it for a single picture in a layout. For hundreds or thousands of pictures, use the image gallery, which draws through the same service.

ui.Image takes an asset.Source. The view does no I/O itself: an application wide image pipeline loads, decodes and caches the picture in the background. Until the picture is ready, the view draws a placeholder.

Image Image
wide := pictures[2] // a 360 x 200 picture
well := ui.Fade(ui.ColorLabel, 0.06)

caption := func(pic gift.View, s string) gift.View {
	return ui.VStack(
		pic,
		ui.Text(s).FontSize(13).Foreground(ui.ColorSecondaryLabel),
	).Gap(8).Align(geom.Alignment{X: 0.5})
}

return ui.HStack(
	caption(ui.Image(wide).Fit(ui.FitContain).Frame(112, 112).Background(well), "FitContain"),
	caption(ui.Image(wide).Fit(ui.FitCover).Frame(112, 112).Background(well), "FitCover"),
	caption(ui.Image(wide).Fit(ui.FitStretch).Frame(112, 112).Background(well), "FitStretch"),
	caption(ui.Image(pictures[1]).Fit(ui.FitCover).Frame(112, 112).
		CornerRadius(20).Clip(true), "Rounded"),
	caption(ui.Image(asset.File("missing.png")).Frame(112, 112).
		CornerRadius(20).Placeholder(well), "Placeholder"),
).Gap(20)

Full demo on GitHub ↗ · run it with go run ./docs/gallery -demo image

Usage

Install the pipeline

Pictures reach the screen through one asset.Pipeline, which you create once and install with ui.SetImagePipeline. Wire its Deliver field to app.Post, so that finished pictures arrive on the UI goroutine. The application owns the pipeline: close it when the program ends, then run app.DrainPosts once more, because the closures Close delivers still have to run.

app := gift.New(gift.Options{Root: root})

cache, _ := os.UserCacheDir()
pipe := asset.NewPipeline(asset.Config{
	Deliver: app.Post,
	Disk:    asset.DiskCacheConfig{Dir: filepath.Join(cache, "myapp", "thumbnails")},
})
defer func() {
	pipe.Close()
	app.DrainPosts()
}()
ui.SetImagePipeline(pipe)

Every other field of asset.Config has a default when left zero. Do not leave Deliver out in an application: without it, results run on a worker goroutine instead of the UI goroutine, which is only meant for tests. An empty Disk.Dir switches the persistent thumbnail cache off. Without an installed pipeline, every image draws its placeholder, which is a quiet, normal state and not an error.

Sources

asset.File and asset.HTTP create a source from a path or a URL. Neither performs I/O, so you can build a list of sources in a view function. A relative path is resolved against the working directory at the time of the call. For pictures stored elsewhere, implement the asset.Source interface: Metadata without I/O and Open returning a fresh reader.

ui.Image(asset.File("photos/beach.jpg"))
ui.Image(asset.HTTP("https://example.com/cover.png"))

The built-in decoders read JPEG and PNG. asset.RegisterDecoder adds further formats.

Size and fit

Without a Frame, an image takes the largest size with the picture’s aspect ratio that fits the space it is offered. Along the main axis of a stack or a scroll view, where one axis is bounded and the other is not, it takes the bounded axis whole and derives the other from the aspect ratio: a picture in a VStack is as wide as the stack and as high as its ratio asks for. Only with no bounded axis at all does an image without a size collapse to zero.

asset.File and asset.HTTP do not know the dimensions before the pipeline has probed the picture. Until then, the image fills a bounded box, measures as a square of the bounded axis along a free one, and reflows once the dimensions arrive. Give it a Frame to keep the layout stable from the first frame.

Fit decides how the picture fills that frame:

FitEffect
ui.FitContainThe whole picture is visible, the rest of the frame stays empty. The default.
ui.FitCoverThe picture covers the frame, the overhang is cropped evenly on both sides.
ui.FitStretchThe picture fills the frame exactly and is distorted.

The pipeline delivers thumbnails, not the original. By default the view asks for the size it is drawn at in device pixels, and the pipeline snaps that to a rung of asset.Config.Sizes, which defaults to 128, 256 and 512. The largest rung caps the resolution, so a picture drawn larger than 512 device pixels is magnified. Add a larger rung to Sizes if you show big pictures. A rung never enlarges a picture: a source smaller than the rung keeps its own size. Size asks for a fixed number of device pixels on the longest edge instead.

Rounded corners

CornerRadius alone rounds the background, the border and the placeholder, but the picture keeps square corners. Add Clip(true) to round the picture as well. With FitContain, the rounding applies to the letterboxed picture itself, not to the empty frame around it.

ui.Image(asset.File("avatar.png")).
	Fit(ui.FitCover).
	Frame(48, 48).
	CornerRadius(24).
	Clip(true).
	Label("Profile picture")

Label sets the accessible name. For a picture, that is its description.

Placeholder

Placeholder sets the color drawn until the picture is resident. The default is a faint white wash, which barely shows on a light background. A faded semantic color works in both themes:

ui.Image(src).Frame(48, 48).Placeholder(ui.Fade(ui.ColorLabel, 0.08))

A transparent placeholder draws nothing. A picture that fails for good, for example a missing file, keeps its placeholder and is not requested again. To try it again, for example after the user pressed reload, call Forget on the pipeline and ui.ForgetImage with the picture’s ID. When a picture changed, call Invalidate on the pipeline and ui.ForgetImage. The ID is src.Metadata().ID. ui.ForgetImage schedules no layout by itself, so call it next to a state change that lays the image out again; see Images.

Tint multiplies the picture with a color. The default, opaque white, leaves it as it is; a lower alpha fades it over its background.

API

Constructors

ConstructorDescription
func Image(src asset.Source) ImageViewImage returns a view of src.

Methods

MethodDescription
Fit(f ImageFit) ImageViewFit selects how the picture is mapped onto the view; see ImageFit.
Label(s string) ImageViewLabel sets the accessible name, which for a picture is its description; see gift.Element.Label.
Placeholder(c Color) ImageViewPlaceholder fills the view until the picture is resident.
Size(px int) ImageViewSize asks the pipeline for a thumbnail of this many device pixels on the longest edge.
Tint(c Color) ImageViewTint multiplies the picture.

Common modifiers: Background, Border, Clip, CornerRadius, Flex, Frame, Key, MaxHeight, MaxWidth, MinHeight, MinWidth, Padding, PaddingInsets, Shadow. See Modifiers.

ui.ImageView on pkg.go.dev ↗

ImageFit selects how a picture is mapped onto its frame. Its constants FitContain, FitCover and FitStretch are described under Size and fit.

FunctionDescription
func ForgetImage(id asset.ID)ForgetImage drops everything the user interface remembers about one picture: the settled request state of Image and the resident textures of every revision of it.
func ImagePipeline() *asset.PipelineImagePipeline returns the pipeline installed by SetImagePipeline, or nil.
func SetImagePipeline(p *asset.Pipeline)SetImagePipeline installs the application wide image pipeline that Image and every Gallery draw through.

The configuration of the pipeline is documented in package asset.

Related

  • Image gallery: many pictures, virtualized, through the same pipeline
  • Icon: monochrome symbols tinted with a color
  • Images: how the pipeline loads, caches and uploads pictures
  • Modifiers: Frame, CornerRadius, Clip and the other shared modifiers
  • Gallery example: a photo browser built on ui.ImageGallery