# How to Load and Use Multiple Fonts with ImFontAtlas in Dear ImGui

> Master loading multiple fonts in Dear ImGui. Learn to use ImFontAtlas, AddFontFromFileTTF, configure ImFontConfig, and build your font atlas for stunning UI. Boost your projects today.

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

---

**TLDR:** Call `ImGuiIO::Fonts->AddFontFromFileTTF()` or `AddFontFromMemoryTTF()` for each font before the first frame, configure glyph ranges and oversampling via `ImFontConfig`, then invoke `Build()` to generate the texture atlas that GPU backends upload with `SetTexID()`.

The **ImFontAtlas** class in the **ocornut/imgui** repository aggregates multiple font sources into a single GPU texture, managing rasterization, packing, and UV coordinate generation. Understanding how to load and use multiple fonts with ImFontAtlas allows you to implement multilingual support, icon fonts, and typographic hierarchy. This guide references the actual source implementation to demonstrate the complete workflow from file loading to texture upload.

## Accessing the Font Atlas

Every Dear ImGui context exposes its font atlas through the `ImGuiIO` structure. Retrieve the atlas before the first rendering frame to ensure the texture is ready for GPU upload.

```cpp
ImGuiIO& io = ImGui::GetIO();
ImFontAtlas* atlas = io.Fonts;

```

The `io.Fonts` pointer provides access to all loading and configuration methods defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) around line 3713.

## Loading Fonts from Files and Memory

The atlas provides distinct methods for loading fonts from disk versus memory buffers. Each returns an `ImFont*` pointer that you store for later activation with `PushFont()` and `PopFont()`.

### Loading TrueType Fonts from Disk

The `AddFontFromFileTTF()` function loads and rasterizes a font file according to the specified pixel size:

```cpp
ImFont* bodyFont = io.Fonts->AddFontFromFileTTF("Roboto-Regular.ttf", 16.0f);
ImFont* headerFont = io.Fonts->AddFontFromFileTTF("Roboto-Bold.ttf", 24.0f);
ImFont* iconFont = io.Fonts->AddFontFromFileTTF("material-icons.ttf", 20.0f);

```

### Loading from Memory Buffers

For embedded resources or dynamically loaded files, use `AddFontFromMemoryTTF()`:

```cpp
ImFont* font = io.Fonts->AddFontFromMemoryTTF(ttfData, ttfSize, 18.0f);

```

According to the source code at [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) line 3714, this function takes ownership of the memory buffer by default. Set `FontDataOwnedByAtlas = false` in the config struct to retain ownership and prevent the atlas from freeing your buffer.

## Configuring Fonts with ImFontConfig

The `ImFontConfig` struct, defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) around line 3600, controls rasterization quality, glyph subsets, and memory ownership flags.

### Oversampling and Sizing

Increase oversampling for sharper text at scaled resolutions:

```cpp
ImFontConfig cfg;
cfg.OversampleH = 3;
cfg.OversampleV = 3;
cfg.SizePixels = 20.0f;
ImFont* crispFont = io.Fonts->AddFontFromFileTTF("font.ttf", 20.0f, &cfg);

```

### Restricting Glyph Ranges

Limiting Unicode ranges reduces texture memory and build time. The `GlyphRanges` field expects a zero-terminated array of `ImWchar` pairs defining inclusive ranges:

```cpp
ImFontConfig cfg;
static const ImWchar ranges[] = { 0x0020, 0x00FF, 0x0400, 0x044F, 0 }; // Latin + Cyrillic
cfg.GlyphRanges = ranges;
ImFont* localizedFont = io.Fonts->AddFontFromFileTTF("arial.ttf", 16.0f, &cfg);

```

**Critical:** As warned in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) line 3699, the glyph range array must remain valid until `Build()` is called because the atlas stores only a pointer, not a copy.

## Managing Multiple Fonts and Custom Glyphs

When using several fonts simultaneously, you can also reserve space for non-font graphics such as colored icons.

### Adding Custom Rectangles for Icons

Reserve texture space using `AddCustomRect()`, declared in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) lines 3889-3892:

```cpp
ImFontAtlasRect rect;
ImFontAtlasRectId iconId = io.Fonts->AddCustomRect(64, 64, &rect);

```

After building the atlas, retrieve the UV coordinates:

```cpp
io.Fonts->Build();
io.Fonts->GetCustomRect(iconId, &rect);
// rect.uv0 and rect.uv1 now contain normalized coordinates for ImDrawList::AddImage()

```

### Handling Font Data Ownership

When using `AddFontFromMemoryTTF()`, the atlas assumes ownership of the buffer unless configured otherwise:

```cpp
ImFontConfig cfg;
cfg.FontDataOwnedByAtlas = false;  // Keep the buffer valid yourself
ImFont* font = io.Fonts->AddFontFromMemoryTTF(myBuffer, bufferSize, 16.0f, &cfg);

```

## Building and Uploading the Atlas Texture

The atlas remains virtual until explicitly built. Any call that modifies the atlas—adding fonts, changing configs, or adding custom rects—requires a rebuild.

### Generating the Pixel Buffer

Call `Build()` to pack all glyphs and rectangles, then retrieve the raw pixels:

```cpp
io.Fonts->Build();

unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);

```

For memory-constrained backends, use `GetTexDataAsAlpha8()` to generate a single-channel texture instead.

### GPU Integration

Upload the buffer to your renderer, then inform ImGui of the texture identifier:

```cpp
GLuint textureID = create_gpu_texture(pixels, width, height, GL_RGBA);
io.Fonts->SetTexID((ImTextureID)(intptr_t)textureID);

```

The atlas also exposes `TexDesiredFormat` if you need to force a specific pixel format before building.

## Enabling FreeType for Advanced Rasterization

For superior hinting, subpixel rendering, or advanced typographic features, enable the optional FreeType backend located in [`misc/freetype/imgui_freetype.cpp`](https://github.com/ocornut/imgui/blob/main/misc/freetype/imgui_freetype.cpp):

```cpp
#define IMGUI_ENABLE_FREETYPE
#include "imgui.h"

// After ImGui::CreateContext():
io.Fonts->SetFontLoader(ImGui::GetFreeTypeFontLoader());

```

This redirects all `AddFont*` calls through FreeType instead of the default stb_truetype rasterizer.

## Summary

- Access the global atlas via `ImGui::GetIO().Fonts` before the first frame.
- Load multiple fonts using `AddFontFromFileTTF()` for disk files or `AddFontFromMemoryTTF()` for embedded data.
- Configure rasterization quality, glyph subsets, and memory ownership through `ImFontConfig` (defined in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) around line 3600).
- Ensure glyph range arrays and font data buffers remain valid until `Build()` completes (as noted in [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) line 3699).
- Reserve custom rectangles with `AddCustomRect()` for icons or user graphics, retrieving UVs after the build.
- Generate the texture with `Build()` or `GetTexDataAsRGBA32()`, upload to GPU, and register the handle via `SetTexID()`.
- Optionally enable FreeType via `SetFontLoader()` for higher-quality rasterization.

## Frequently Asked Questions

### Can I add fonts after the first frame has rendered?

No. Adding fonts or modifying configurations invalidates the texture coordinates and pixel buffer. You must call `Build()` again and re-upload the resulting texture to the GPU, which typically requires recreating dependent GPU resources. Perform all font loading during application initialization.

### Why are my Cyrillic or CJK characters rendering as blank squares?

The default glyph range only includes Basic Latin. Specify the appropriate range in `ImFontConfig::GlyphRanges` using built-in helpers like `GetGlyphRangesCyrillic()`, `GetGlyphRangesJapanese()`, or `GetGlyphRangesChineseFull()`, or define a custom range array. Verify that your TTF/OTF file actually contains glyphs for the target Unicode blocks.

### How do I switch between multiple fonts during UI rendering?

Store the `ImFont*` pointers returned by `AddFont*` calls. Activate a specific font by calling `ImGui::PushFont(myFont)` before your widget code, then `ImGui::PopFont()` after. Never call `PushFont` with a null pointer, and always ensure proper stack balancing.

### Does AddFontFromMemoryTTF copy the font data?

By default, yes—the atlas takes ownership and will free the memory using `IM_FREE()`. To retain ownership of the buffer, set `cfg.FontDataOwnedByAtlas = false` in the `ImFontConfig` struct passed to the function, as documented at [`imgui.h`](https://github.com/ocornut/imgui/blob/main/imgui.h) line 3714.