Table of Contents

Image Loading

Xui's image API mirrors HTMLImageElement in the browser: acquire a handle, set the source, draw.

Acquiring an image handle

Images are transient services — each call returns a new handle backed by the platform's cached pipeline:

protected override void OnAttach(ref AttachEventRef e)
{
    image = this.GetService<IImage>();
    image?.Load("Assets/photo.png");
}

protected override void OnDetach(ref DetachEventRef e)
{
    image = null;
}

GetService<IImage>() walks up the view tree to the window's platform runtime, which vends a DirectXImage (on Windows) backed by DirectXImageFactory.

Loading

image.Load("Assets/photo.png");            // sync — instant if cached, blocks on first load
await image.LoadAsync("Assets/photo.png"); // async — first decode on background thread

Paths are resolved relative to AppContext.BaseDirectory. Absolute paths are also accepted.

The factory caches decoded images by URI — subsequent Load calls with the same path return instantly.

Drawing

protected override void RenderCore(IContext context)
{
    if (image is null || image.Size == Size.Empty) return;

    // stretch to fill a rect
    context.DrawImage(image, this.Frame);

    // with opacity
    context.DrawImage(image, destRect, opacity: 0.5f);

    // source sub-region
    context.DrawImage(image, sourceRect, destRect, opacity: 1f);
}

Pattern fill

Use an image as a repeating fill for any path:

context.SetFill(new ImagePattern(image));                          // tile in both axes
context.SetFill(new ImagePattern(image, PatternRepeat.RepeatX));   // tile horizontally only
context.SetFill(new ImagePattern(image, PatternRepeat.NoRepeat));  // single image, no tile

context.BeginPath();
// ... build any path ...
context.Fill();

ImagePattern is a ref struct — it is never boxed.

Device-lost recovery

On Windows, if the D3D device is lost (GPU reset, driver update), the platform runtime calls DirectXImageFactory.Rehydrate(), which re-uploads all cached images to the new device. Existing IImage handles remain valid — their internal resource pointer is updated in-place.

Application code does not need to handle device-lost explicitly.

Built-in ImageView

For simple image display, use ImageView instead of writing RenderCore yourself:

var view = new ImageView { Source = "Assets/photo.png" };

ImageView acquires IImage via GetService<IImage>() in OnActivate, loads on Source set, and scales to fit while preserving aspect ratio.