zgui

Images

Load raster images from files or memory, control their size, and understand decoding and caching.

The image element loads encoded raster data and draws it in its content box. The standard app wiring supports PNG, JPEG, WebP, and GIF. For GIF, zgui draws the first frame.

Load a file

Set src to a file-system path:

use zgui::prelude::*;

view! {
    image(
        class = "avatar",
        src = "assets/avatar.webp",
        a11y:label = "Ada Lovelace",
    )
}
.avatar {
    width: 96px;
    height: 96px;
    border-radius: 50%;
    overflow: hidden;
}

src is a local path, not an HTTP URL. zgui first reads the image header to get the natural size. It does not decode pixels for this step. After layout gives the element a content box, zgui decodes a suitable resolution off the UI thread. Each completion wakes the frame loop. The image can get its natural size before its pixels are ready.

The source can be reactive:

image(src = move || selected_path.get())

Changing or removing src detaches the old content. A failed source stays blank. zgui writes a warning with the zgui::images tracing target and does not retry the same failed source each frame.

Load bytes from memory

Use zgui_image::ImageBytes when no file path exists. Add the matching workspace crate to the application:

Cargo.toml
[dependencies]
zgui = { git = "https://github.com/zortax/zgui" }
zgui-image = { git = "https://github.com/zortax/zgui" }
let picture = zgui_image::ImageBytes::new(include_bytes!("avatar.png"));
let src = picture.url();

let view = image(src = src);

Keep picture alive while the element can need the bytes. The URL is a registry key. Dropping the last ImageBytes clone unregisters the data. A later decode of that URL then fails.

Sizing

The source pixel dimensions are the natural size in CSS pixels. A 640 by 480 file has a natural size of 640 by 480 CSS pixels and a 4:3 natural ratio. The natural size does not change with the window scale factor or with the resolution that zgui decodes for display.

CSS still has final control:

.preview { width: 100%; aspect-ratio: 16 / 9; }

Use object-fit to control how the picture meets its content box. Its initial value is fill.

.avatar  { width: 96px; height: 96px; object-fit: cover; }
.preview { width: 480px; height: 320px; object-fit: contain; }
.stamp   { width: 160px; height: 120px; object-fit: none; object-position: 100% 0%; }
ValueResult
fillStretches the picture to the box. The aspect ratio can change.
containPreserves the ratio and fits the whole picture in the box.
coverPreserves the ratio and fills the box. The box clips the excess.
noneUses the natural size. The box can clip the picture.
scale-downUses the smaller result of none and contain.

object-position places a fitted picture in the space that remains. Its initial value is 50% 50%. Percentages and lengths are supported. Rounded corners and the element's content frame clip the fitted picture. A contain letterbox shows the element background.

Before the header probe finishes, an image has no natural width or height. Give layout an explicit size when a late size change is not acceptable.

Display-sized decoding and cache sharing

zgui measures the laid-out content box in device pixels and decodes for that demand. A thumbnail does not keep the source-resolution pixels in memory. The fit mode is part of the demand: fill, contain, and scale-down need no more detail than the box; cover includes the part of the scaled picture that the box clips; and none requests the source at the display scale.

The loader rounds the long edge up through size classes: 64, 128, 256, 512, 1024, and 2048 device pixels. This prevents a one-pixel layout change from starting another decode. A demand above the ladder uses the source size, up to the GPU device's texture limit. The decoder never upscales past the source resolution.

The source string identifies an image. Elements with the same source share the best sufficient decoded variant and its texture tile. A larger use can add a larger size-class variant; it does not decode once per element. While that decode runs, zgui continues to draw the best smaller variant.

Variants up to a 512-pixel long edge share filtered atlas textures. Larger variants get a texture with mip levels, which keeps minification smooth. After an upload, zgui releases large decoded host buffers. It keeps small buffers of at most 64 KiB because they are cheap to retain. If eviction or device loss removes a tile whose host buffer was released, zgui decodes that variant again.

The memory budget removes unused variants before active ones and removes unused sources from the coldest to the newest. The probed natural size remains, so cache eviction does not change layout.

Code that calls zgui_image::decode or decode_scaled directly chooses Limits; its default maximum dimension is 2048 pixels. The standard app instead uses the current GPU device limit.

Decoded texels are premultiplied, gamma-encoded sRGB RGBA. They are tightly packed, with the top row first. This detail matters only to code that works with zgui-image directly.

Accessibility

alt is stored as an ordinary attribute, but the accessibility tree does not use it. Set a11y:label for meaningful content. Set a11y:hidden = true for decorative content.

On this page