ExternalTexture
An external texture is one shared producer identity. Platform-specific classes derive from ExternalTexture; pass their std::shared_ptr directly to Image. There is no separate source-to-handle conversion.
Choose a producer
Section titled “Choose a producer”| Platform | Producer choices |
|---|---|
| Windows | windows::PixelTexture for copied CPU rows; windows::D3D11Texture for immutable shared GPU snapshots. |
| Android | android::BitmapTexture, android::GlTexture, or android::SurfaceStreamTexture. |
| iOS / macOS | PixelBufferTexture for Core Video frames; MetalTexture for GPU snapshots in the platform namespace. |
| Linux | linux::PixelTexture, linux::GlTexture, or linux::GdkTexture. |
| Web | web::VideoFrameTexture for a browser VideoFrame. |
Include the matching platform header explicitly. These producer types are not interchangeable across renderer backends.
A software frame on Windows
Section titled “A software frame on Windows”This integration fragment receives an existing RGBA byte span:
auto texture = std::make_shared<windows::PixelTexture>(Size{320.0F, 180.0F});texture->Publish({ .pixel_width = 640, .pixel_height = 360, .bytes_per_row = 640 * 4, .format = windows::PixelFormat::Rgba8888, .pixels = pixels,});View preview = Image(texture).Fit(ImageFit::Contain);PixelTexture::Publish copies required rows before returning, so this producer may reuse the source bytes. The input is straight-alpha untagged sRGB; the renderer receives its owned representation. Do not generalize this CPU-copy rule to all platform objects.
GPU ownership matters
Section titled “GPU ownership matters”Windows D3D11 and Apple Metal publication create stable snapshots; serialize producer access as required by the concrete header. D3D11 needs a supported single-sampled BGRA source and matching graphics adapter, and is unavailable in Windows 7 compatibility builds.
Android/Linux GlTexture::PublishCurrent runs with the producer context current and publishes a stable copied snapshot. Linux GdkTexture instead retains an already immutable GDK texture: the application must not mutate its backing content afterward. Web publication follows the browser event-loop and VideoFrame lifetime contract.
Keep device/context loss, fences, and platform handles out of shared UI code. A module can expose a typed producer while owning the platform-specific work.
Separate layout from frames
Section titled “Separate layout from frames”Intrinsic size is set once in logical DIPs. The published pixel dimensions may change without changing that layout intent. Replace the texture identity if logical size really changes.
Publication schedules repaint without recomposition or paint-sequence rerecording. IsActive() helps avoid unnecessary production, but it is not an unmount callback. Stop work explicitly in your service/lifecycle cleanup, then call Finish(); the last published frame remains available to consumers.
Verify on the actual backend
Section titled “Verify on the actual backend”Test first publication, empty producer, changing frame resolution, hidden consumers, replacement, unmount, shutdown, context/device loss, and publication from the documented thread. A shared-header compile is not GPU or device validation.
Use PlatformView instead when the embedded object must own platform-control interaction. See the platform-specific reference for includes.

