# How to Display Custom Images Using ImTextureID in ImGui

> Learn to display custom images in ImGui using ImTextureID. Understand how this opaque handle connects your GPU textures with ImGui rendering for seamless integration. Maximize visual appeal in your applications.

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

---

**`ImTextureID` is an opaque, backend-specific handle (such as an OpenGL `GLuint`, DirectX `ID3D11ShaderResourceView*`, or Vulkan `VkDescriptorSet`) that you cast from your native GPU texture and pass to `ImGui::Image()` to render custom images uploaded with your own graphics code.**

In the `ocornut/imgui` immediate-mode GUI library, displaying custom images requires bridging your renderer's native texture objects with ImGui's drawing API. Since ImGui is graphics-API agnostic, it relies on `ImTextureID` to store references to GPU textures without knowing the underlying implementation details. This article explains how to obtain, cast, and use these identifiers across major rendering backends.

## What is ImTextureID?

In [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h), the default type definition is `typedef ImU64 ImTextureID;`, creating a 64-bit value capable of storing either an integer or a pointer depending on the backend's requirements. Each official backend in the `backends/` directory reinterprets this value according to its native resource type:

- **OpenGL 3**: Uses a `GLuint` texture name
- **DirectX 11**: Expects an `ID3D11ShaderResourceView*` pointer
- **Vulkan**: Stores a `VkDescriptorSet` handle
- **SDL Renderer**: Uses `SDL_Texture*`

The newer `ImTextureRef` type provides additional safety wrappers, but the underlying principle remains identical: ImGui treats the value as an opaque token and passes it directly to the backend's rendering implementation.

## The Three-Step Workflow

To display a custom image, you must handle GPU resource management yourself before involving ImGui:

1. **Upload**: Load your image data and create a GPU texture using your renderer's API (OpenGL, DirectX, Vulkan, etc.)
2. **Cast**: Convert the native texture handle to `ImTextureID` using a simple cast
3. **Draw**: Pass the ID to `ImGui::Image()` or `ImGui::ImageButton()`

During the render loop, ImGui stores this ID in an `ImDrawCmd` structure. The backend's `RenderDrawData()` function retrieves it via `ImDrawCmd::GetTexID()` and binds the corresponding GPU resource before issuing the draw call.

## Backend-Specific Implementation Examples

The exact casting depends on your graphics API. Here are minimal implementations for three major backends.

### OpenGL 3

After uploading your image with `glTexImage2D` or similar, you receive a `GLuint` texture ID. Cast this directly to `ImTextureID`:

```cpp
// Your OpenGL upload code produces: GLuint myTexture;
ImTextureID tex_id = (ImTextureID)myTexture;

ImGui::Begin("Custom Image");
ImGui::Image(tex_id,
             ImVec2(256, 256),                // display size
             ImVec2(0, 0), ImVec2(1, 1),     // UV coordinates (full texture)
             ImVec4(1,1,1,1),                // tint color (white = no tint)
             ImVec4(0,0,0,0));               // border color (transparent)
ImGui::End();

```

As documented in [`backends/imgui_impl_opengl3.h`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_opengl3.h), the backend expects `ImTextureID` to contain a valid OpenGL texture name.

### DirectX 11

For DirectX 11, you create an `ID3D11ShaderResourceView` from your texture and cast the pointer:

```cpp
// Your D3D11 code produces: ID3D11ShaderResourceView* srv;
ImTextureID tex_id = (ImTextureID)srv;

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

```

The DirectX 11 backend implementation in [`backends/imgui_impl_dx11.h`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_dx11.h) dereferences this pointer to set the shader resource view before drawing.

### Vulkan

Vulkan requires descriptor sets for binding textures. Use the descriptor set returned by `ImGui_ImplVulkan_AddTexture()` or your own allocation:

```cpp
// VkDescriptorSet ds = ... (created via ImGui_ImplVulkan_AddTexture or manual)
ImTextureID tex_id = (ImTextureID)ds;

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

```

According to [`backends/imgui_impl_vulkan.h`](https://github.com/ocornut/imgui/blob/main/backends/imgui_impl_vulkan.h), the backend binds this descriptor set during command buffer recording.

### General Pattern

Regardless of backend, the ImGui API remains consistent:

```cpp
ImTextureID myTexID = /* your native handle */;
ImGui::Begin("Image Window");
ImGui::Image(myTexID, ImVec2(width, height));
ImGui::End();

```

Only the method of obtaining and casting the native handle changes between renderers.

## Rendering Pipeline Details

Internally, ImGui stores texture references in `ImDrawCmd` structures defined in [`imgui_internal.h`](https://github.com/ocornut/imgui/blob/main/imgui_internal.h). When you call `ImGui::Image()`, the library creates a draw command containing the `ImTextureID` you provided. 

During the backend's `RenderDrawData()` implementation (found in files like [`imgui_impl_opengl3.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_opengl3.cpp) or [`imgui_impl_dx11.cpp`](https://github.com/ocornut/imgui/blob/main/imgui_impl_dx11.cpp)), the code iterates through draw commands and retrieves the texture ID:

```cpp
// Conceptual backend code
ImTextureID tex_id = draw_cmd->GetTexID();
// Backend binds the appropriate GPU resource using tex_id

```

This abstraction allows ImGui to remain graphics-API neutral while supporting hardware-accelerated texture rendering.

## Safety Conventions and Invalid Textures

By default, ImGui considers zero (`0` or `nullptr`) as an invalid texture ID. If you store texture indices, offsets, or custom handles in `ImTextureID`, define `ImTextureID_Invalid` in your [`imconfig.h`](https://github.com/ocornut/imgui/blob/main/imconfig.h) file to avoid collisions with this convention:

```cpp
// In imconfig.h
#define ImTextureID_Invalid ((ImTextureID)-1)

```

This prevents ImGui from interpreting your valid texture index `0` as "no texture."

## Summary

- **`ImTextureID`** is a 64-bit opaque value defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) that stores backend-specific texture handles
- **Cast your native GPU handle** (OpenGL `GLuint`, DirectX `ID3D11ShaderResourceView*`, Vulkan `VkDescriptorSet`, etc.) to `ImTextureID` before passing it to `ImGui::Image()`
- **ImGui does not load images**; you must upload image data to the GPU using your own renderer code
- **Backends consume the ID** during `RenderDrawData()` by calling `ImDrawCmd::GetTexID()` and binding the corresponding resource
- **Define `ImTextureID_Invalid`** in [`imconfig.h`](https://github.com/ocornut/imgui/blob/main/imconfig.h) if you use non-pointer values to avoid the zero-is-invalid convention

## Frequently Asked Questions

### What type should I cast my texture handle to?

Cast your native texture handle directly to `ImTextureID` (which is `ImU64` by default). For OpenGL, cast your `GLuint` to `ImTextureID`; for DirectX 11, cast your `ID3D11ShaderResourceView*` pointer; for Vulkan, cast the `VkDescriptorSet`. The backend reinterprets the 64-bit value appropriately.

### Does ImGui load images from disk for me?

No. ImGui is a GUI library only and does not handle image loading, decoding, or GPU upload. You must load image files (PNG, JPG, etc.) using a library like stb_image, upload the data to your GPU with OpenGL, DirectX, Vulkan, or other APIs, then pass the resulting native handle to ImGui as an `ImTextureID`.

### Why is my texture showing as black or white in ImGui?

If your texture appears solid black or white, ensure your image data uploaded successfully to the GPU and that you are passing the correct native handle. Also verify that your UV coordinates (the third and fourth parameters to `ImGui::Image()`) map to valid regions of your texture—using `(0,0)` to `(1,1)` displays the full texture.

### Can I use multiple different textures in one ImGui window?

Yes. You can call `ImGui::Image()` with different `ImTextureID` values as many times as needed within a single window. ImGui automatically generates separate draw commands with the appropriate texture IDs, and the backend handles binding the correct texture for each draw call during rendering.