# How to Display Images Using ImTextureID in Dear ImGui

> Learn how to display images with ImTextureID in Dear ImGui. Cast native GPU resources to ImTextureID and pass to ImGui::Image for immediate mode UI rendering.

- Repository: [omar/imgui](https://github.com/ocornut/imgui)
- Tags: how-to-guide
- Published: 2026-07-25

---

**ImTextureID is a backend-specific texture handle that you cast from native GPU resources—such as an OpenGL texture name, a Vulkan descriptor set, or a DirectX shader resource view—and pass to `ImGui::Image()` to render the image within your immediate-mode UI.**

Dear ImGui (ocornut/imgui) does not contain any image-loading code. Instead, it relies on your rendering backend to manage GPU textures and exposes a lightweight abstraction called **ImTextureID** (defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h)) that references those native resources. During the UI rendering pass, Dear ImGui stores this identifier inside draw commands (`ImDrawCmd::TexID`) so the backend can bind the correct texture before issuing draw calls.

## Understanding ImTextureID

In [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) at line 339, `ImTextureID` is defined as a 64-bit integer type that can hold either a pointer or an integer handle:

```cpp
typedef ImU64 ImTextureID;    // Default: a 64-bit value for pointer or integer handles
// void* ImTextureID;           // Alternative: if you define ImTextureID as a pointer in imconfig.h

```

This type is deliberately opaque. Dear ImGui never interprets the value; it merely stores it and passes it back to your backend during rendering. The actual meaning depends entirely on which graphics API you use.

## Backend-Specific Texture Types

Each official backend documents what native type it expects for `ImTextureID`. You must cast your GPU resource handle to `ImTextureID` using an appropriate cast (typically `(ImTextureID)(intptr_t)` or direct pointer casts).

- **OpenGL 3 (GLSL)**: `GLuint` texture names.
- **Vulkan**: `VkDescriptorSet` obtained via `ImGui_ImplVulkan_AddTexture()`.
- **DirectX 11**: `ID3D11ShaderResourceView*`.
- **DirectX 12**: `D3D12_GPU_DESCRIPTOR_HANDLE` or similar descriptor handles.
- **SDL2/SDL3 Renderer**: `SDL_Texture*`.

Reference the backend headers (e.g., [`imgui_impl_opengl3.h`](https://github.com/ocornut/imgui/blob/main/imgui_impl_opengl3.h), [`imgui_impl_vulkan.h`](https://github.com/ocornut/imgui/blob/main/imgui_impl_vulkan.h), [`imgui_impl_dx11.h`](https://github.com/ocornut/imgui/blob/main/imgui_impl_dx11.h)) to confirm the expected type for your specific rendering backend.

## Displaying Images with ImGui::Image

The primary widget for rendering an image is `ImGui::Image()`, implemented in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp). Its signature accepts texture coordinates for UV mapping, tint colors, and border colors:

```cpp
void ImGui::Image(
    ImTextureID tex_id,
    const ImVec2& size,
    const ImVec2& uv0 = ImVec2(0, 0),
    const ImVec2& uv1 = ImVec2(1, 1),
    const ImVec4& tint_col = ImVec4(1, 1, 1, 1),
    const ImVec4& border_col = ImVec4(0, 0, 0, 0)
);

```

`ImGui::ImageButton()` uses an identical signature but additionally handles button input logic. Both functions pack the provided `tex_id` into an `ImDrawCmd` structure that the backend reads during `ImDrawCmd::TexID` processing.

### OpenGL 3 Example

Load an image with `stb_image`, create a texture, then cast the `GLuint` to `ImTextureID`:

```cpp
// Load image data
int w, h, channels;
unsigned char* data = stbi_load("avatar.png", &w, &h, &channels, 4);
if (!data) return;

// Create OpenGL texture
GLuint gl_texture;
glGenTextures(1, &gl_texture);
glBindTexture(GL_TEXTURE_2D, gl_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(data);

// Cast to ImTextureID
ImTextureID my_texture_id = (ImTextureID)(intptr_t)gl_texture;

// Render in ImGui
ImGui::Begin("Image Viewer");
ImGui::Image(my_texture_id, ImVec2((float)w, (float)h));
ImGui::End();

```

### Vulkan Example

Register your `VkImageView` and `VkSampler` with the backend, which returns a `VkDescriptorSet` that serves as the `ImTextureID`:

```cpp
// Create your VkImageView and VkSampler elsewhere...

VkDescriptorSet descriptor_set = ImGui_ImplVulkan_AddTexture(
    sampler, 
    image_view, 
    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
);

ImTextureID tex_id = (ImTextureID)descriptor_set;

ImGui::Begin("Vulkan Texture");
ImGui::Image(tex_id, ImVec2(300, 200));
ImGui::End();

```

### DirectX 11 Example

Pass your `ID3D11ShaderResourceView` pointer directly as the texture ID:

```cpp
ID3D11ShaderResourceView* srv = LoadMyTexture("sprite.dds");  // Your loader
ImTextureID tex_id = (ImTextureID)srv;

ImGui::Begin("DX11 Image");
ImGui::Image(tex_id, ImVec2(128, 128));
ImGui::End();

```

### SDL2 Renderer Example

When using the SDL2 rendering backend, cast `SDL_Texture*`:

```cpp
SDL_Surface* surface = IMG_Load("icon.png");
SDL_Texture* sdl_texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_FreeSurface(surface);

ImTextureID tex_id = (ImTextureID)sdl_texture;

ImGui::Begin("SDL Texture");
ImGui::Image(tex_id, ImVec2(80, 80));
ImGui::End();

```

## Texture Lifetime and Synchronization

The GPU texture referenced by `ImTextureID` must remain valid for the entire frame. Dear ImGui queues draw commands, so if you destroy a texture immediately after calling `ImGui::Image()`, the backend will attempt to bind an invalid resource during the subsequent render pass.

Starting with v1.92, Dear ImGui introduces `ImTextureData` structures that backends can use to request asynchronous texture creation. Check `ImTextureData::Status == ImTextureStatus_WantCreate` in your backend code to handle textures that need to be created or uploaded before the draw command executes.

## ImTextureRef vs. ImTextureID (v1.92+)

From v1.92 onward, most internal APIs accept **ImTextureRef**, which is a variant type that can hold either an `ImTextureID` or a pointer to an `ImTextureData` structure. The public `ImGui::Image()` and `ImageButton()` entry points remain backward compatible and still accept raw `ImTextureID` values, ensuring existing code continues to compile while allowing new implementations to leverage the richer texture data interface.

## Summary

- **ImTextureID** is defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) as a 64-bit value capable of storing pointers or integer handles to native GPU textures.
- **Rendering backends** determine the actual type: OpenGL uses `GLuint`, Vulkan uses `VkDescriptorSet`, DirectX uses `ID3D11ShaderResourceView*`, and SDL2 uses `SDL_Texture*`.
- **Rendering workflow**: Create the texture with your graphics API, cast the handle to `ImTextureID`, pass it to `ImGui::Image()` or `ImageButton()`, and ensure the texture lives until the frame is rendered.
- **Implementation location**: The packing of texture IDs into draw commands occurs in [`imgui.cpp`](https://github.com/ocornut/imgui/blob/main/imgui.cpp), while the binding happens in backend-specific render loops that read `ImDrawCmd::TexID` (declared in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h)).

## Frequently Asked Questions

### What image formats does Dear ImGui support?

Dear ImGui does not load or decode image files. You must use a separate library (such as `stb_image`, [`stb_image.h`](https://github.com/ocornut/imgui/blob/main/stb_image.h), or platform-specific APIs) to decode PNG, JPEG, or DDS files into raw pixel buffers, then upload those buffers to your GPU using your graphics API (OpenGL, Vulkan, DirectX, etc.) before obtaining the handle to cast to `ImTextureID`.

### Can I use ImTextureID with custom shaders?

Yes. Since `ImTextureID` is simply a handle passed through to the backend, you can extend your backend's renderer to interpret additional bits of the identifier for custom shader selection or sampler state. However, the standard `ImGui::Image()` API only sets the texture ID; any additional shader parameters must be managed by your application before calling `ImGui::Render()`.

### Why is my image appearing as a white or black square?

A white square typically indicates that the texture failed to load or the `ImTextureID` handle is null. Verify that your texture creation succeeded (check OpenGL error codes, validation layers in Vulkan, or HRESULT in DirectX) and confirm you are casting the handle correctly—e.g., `(ImTextureID)(intptr_t)gl_tex_id` for OpenGL. A black square often indicates incorrect UV coordinates or texture format issues where the alpha channel is zero.

### How do I update a texture every frame for video playback?

Create the texture once (e.g., with `GL_DYNAMIC_DRAW` or `D3D11_USAGE_DYNAMIC`), then update the subresource or texture data each frame before your ImGui calls. Keep the same `ImTextureID` handle throughout; only the GPU memory contents need to change. Ensure you upload the new pixel data before the `ImGui::Image()` call so the backend sees the updated content during rendering.