Images

Introduction

WIP. APIs around ImageRef, SVG, and GPU textures are stable enough to use, but some helpers (e.g. PNG/JPEG decoding) live behind feature flags and may move between crates.

Azul has three sources of pixel content in a DOM tree:

  • Raster image. Backed by a CPU pixel buffer (RawImageFormat). PNG, JPEG, BMP, raw bytes.
  • Vector / SVG. Backed by SvgMultiPolygon plus tessellation. Icons, charts, diagrams.
  • GPU texture. Backed by a Texture produced by callback. OpenGL scenes, custom shaders.

All three end up wrapped in a single ImageRef and inserted into the tree via Dom::create_image(image_ref). The framework hashes the handle for caching and uploads the backing data to the renderer the first time it's shown.

ImageRef

ImageRef is a reference-counted handle to decoded image data. It's Send + Sync. Cloning bumps a refcount; the underlying buffer is freed when the last clone drops. Construct one via:

  • ImageRef::null_image(w, h, format, tag). A placeholder of known size.
  • ImageRef::new_rawimage(raw). Wraps a CPU pixel buffer.
  • ImageRef::gl_texture(texture) (also new_gltexture). Wraps an existing GL texture.
  • ImageRef::callback(cb, data). Defers rendering until layout knows the size.

Inspect with is_null_image, is_raw_image, is_gl_texture, is_callback, is_invalid, get_size, get_hash.

Raster images

Raw pixel data flows through RawImage. The pixel layout is RawImageFormat: R8, RG8, RGB8, RGBA8, R16, RG16, RGB16, RGBA16, BGR8, BGRA8, RGBF32, RGBAF32. Pick the one that matches the source bytes; the renderer converts to its internal format on upload.

use azul::prelude::*;

fn load_pixels() -> Vec<u8> { vec![] }

let bytes: Vec<u8> = load_pixels();
let raw = RawImage {
    pixels: RawImageData::U8(bytes.into()),
    width: 256,
    height: 256,
    premultiplied_alpha: true,
    data_format: RawImageFormat::RGBA8,
    tag: Vec::new().into(),
};
let image_ref = ImageRef::new_rawimage(raw).expect("invalid pixel data");
let dom = Dom::create_image(image_ref);

RawImageData is one of U8, U16, F32. Decoded image dimensions are reported by ImageRef::get_size(). The size is fixed once the buffer is created. To resize at render time, wrap the image in a styled element and let CSS scale the box (set width / height via Dom::with_css or Dom::with_css_property).

A null_image keeps a slot in the cache without uploading data. It's useful as a fallback when an asynchronous loader hasn't finished yet.

RawImage also exposes encoders (encode_png, encode_jpeg, encode_bmp, encode_gif, encode_pnm, encode_tga, encode_tiff) and the universal decoder RawImage::decode_image_bytes_any.

SVG

Vector graphics go through tessellation: every closed path is converted to a triangle list, then rendered on the CPU or uploaded to the GPU. Build paths in memory with SvgPath::create and combine them via SvgMultiPolygon::create. Then call SvgMultiPolygon::tessellate_fill or tessellate_stroke to produce a TessellatedSvgNode.

See SVG for the full geometry model, stroking options, and how to combine multiple polygons into one draw call.

GPU textures and custom drawing

ImageRef::callback(...) defers image production until the layout pass knows the box dimensions. The callback receives a RenderImageCallbackInfo with the available GL context and the laid-out bounds, and returns an ImageRef (typically wrapping a fresh Texture):

use azul::prelude::*;

extern "C" 
fn render(_data: RefAny, mut info: RenderImageCallbackInfo) -> ImageRef {
    let size = info.get_bounds().get_physical_size();
    // allocate a texture, draw into it, return ImageRef::gl_texture(tex)
    ImageRef::null_image(size.width as usize, size.height as usize,
                        RawImageFormat::RGBA8, U8VecRef::from(&[][..]))
}

fn build_dom(state: RefAny) -> Dom {
    Dom::create_image(ImageRef::callback(
        RenderImageCallback::create(render).to_core(),
        state,
    ))
}

See Canvas and GL Textures for the full texture allocation, drawing, and FXAA flow used by the opengl example.

Sizing and aspect ratio

The renderer treats an ImageRef like an <img> tag: it expands to fill its CSS box. To preserve aspect ratio:

  • width: 100px; height: 100px. Stretched to a square.
  • width: 100px (height auto). Scaled to keep the source aspect ratio.
  • flex-grow: 1 (square parent). Fills the parent.

Image content is stretched without filtering hints. For icon-quality output you usually want the source resolution to match the on-screen pixel size.

Updating an image

ImageRef is intern-keyed: passing a clone in two consecutive Doms reuses the same upload. To swap pixels you build a new ImageRef. Drop the old clone if you want the GPU memory freed.

For animation, use a render-image callback (ImageRef::callback) and a timer to flag the DOM for repaint each frame. The callback re-runs and returns a fresh texture; the previous one is freed automatically when the new clone replaces it.

Image masks

ImageMask clips drawn content to an image-defined alpha mask. It carries image: ImageRef, rect: LogicalRect, and repeat: bool. Apply one to a Dom with Dom::with_clip_mask.

Coming Up Next

  • SVG — Parsing and rendering SVG documents
  • GL Canvas — Embedding an OpenGL canvas inside a Dom node
  • Styling with CSS — Stylesheets, selectors, and the cascade

Back to guide index