Загрузка пользовательского TTF-шрифта из статического класса
Как загрузить пользовательский TTF-шрифт из статического класса.
Загрузить TTF через статический класс
Статический класс может подготовить байты шрифта, но не наследует GetService и другие возможности Script.csx. Передадим ему файловый провайдер явно, а рисовать будем в обработчике кадров.
Подготовить шрифт и SDK
Добавьте свой Roboto-Regular.ttf как встроенный ресурс проекта C# Script. Нужен настоящий TTF с нужными символами; имя файла не гарантирует наличие кириллицы. Для примера ниже задайте fontPath полным manifest-именем: при пространстве имён MyScript и файле в корне это MyScript.Roboto-Regular.ttf, при папке Fonts — MyScript.Fonts.Roboto-Regular.ttf. Фактические имена перечисляются в отладочном журнале подготовки скрипта. Не рассчитывайте на поиск любого ресурса по короткому Roboto-Regular.ttf.
Импортируемый исторический пример: https://eyeauras.net/share/S20251017150654moSdG8zUyQ4D. Его ссылка на пакет сохранена:
#r "nuget:EyeAuras.ImGuiSdk, 0.1.17"
Далее показан контракт AddFont / ReplaceFont(ImGuiFontSpec) из исходников EyeAuras 20fd3d4 и PoeEye 0e02c98. Наличие этих методов в опубликованном пакете 0.1.17 здесь не проверено. Перед запуском выберите в своём проекте совместимую версию SDK и проверьте доступность этих символов; историческая ссылка сама по себе этого не доказывает. Если в установленном SDK другой API, не смешивайте примеры разных версий. Карта SDK помогает найти контракты.
Script.csx
В проекте должна быть одна выбранная ссылка на EyeAuras.ImGuiSdk. Код ниже размещается в верхнеуровневом Script.csx живого EyeAuras, где доступны AddNewExtension, GetService, ExecutionAnchors и cancellationToken.
using EyeAuras.ImGuiSdk;
using EyeAuras.Repl;
using ImGuiNET;
using PoeShared.Scaffolding;
{
AddNewExtension<ImGuiContainerExtensions>();
var files = GetService<IScriptFileProvider>();
var fontPath = "MyScript.Roboto-Regular.ttf"; // полное имя вашего ресурса
var fontData = FontData.Load(files, fontPath);
using var osd = GetService<IImGuiExperimentalApi>();
ImGuiFontSpec font = default;
using var rendering = osd.AddRenderer(() =>
{
// И регистрация, и использование шрифта происходят в потоке отрисовки.
if (!font.IsInitialized)
{
font = osd.AddFont(fontData, 20, "Roboto", ImGuiFontRangeType.Cyrillic);
}
ImGuiEx.PushFont(font);
try
{
ImGui.ShowDemoWindow();
}
finally
{
ImGuiEx.PopFont(font);
}
});
// Не завершать выполнение сразу после регистрации обработчика.
cancellationToken.WaitHandle.WaitOne();
}
FontData.cs
Добавьте обычный C# файл в тот же проект. Это собственный вспомогательный класс примера; генерация EmbeddedBinaryData.RobotoRegularTtf хостом для него не требуется.
using EyeAuras.Repl;
using PoeShared.Scaffolding;
public static class FontData
{
public static byte[] Load(IScriptFileProvider files, string manifestName)
{
return files.ReadAllBytes(manifestName);
}
}
Статический метод только читает данные через переданную зависимость. Он не создаёт ImGui-контекст и не должен вызывать ImGui с произвольного потока. Вместо чтения ресурса можно передать уже имеющийся byte[] настоящего TTF — способ получения данных не меняет правила отрисовки.
Когда шрифт появится и кто им владеет
AddFont возвращает ImGuiFontSpec, а не готовый ImFontPtr. Он копирует входные данные и помечает атлас для перестроения. В этой реализации перестроение выполняется после обработчиков текущего кадра, поэтому первый кадр может ещё использовать прежний шрифт. IsInitialized означает регистрацию описания, а не завершение загрузки в атлас.
ImGuiEx.PushFont(font) и ImGuiEx.PopFont(font) работают парой с одним описанием в одном кадре. До появления нативного шрифта оба вызова ничего не делают. Не сохраняйте сырой указатель между перестроениями атласа. Этот вариант выбирает шрифт только на время отрисовки своего содержимого; для основного шрифта есть ReplaceFont.
По умолчанию AddFont использует размер 16 и ImGuiFontRangeType.Default, который обращается к стандартному диапазону ImGui. Здесь явно выбран Cyrillic; диапазон не добавляет отсутствующие в TTF глифы. Точный состав стандартного диапазона и поведение нативного парсера зависят от библиотеки.
Обработчик кадров и экземпляр API принадлежат этому запуску; после остановки using сначала удаляет обработчик, затем освобождает долю общего окна. Это не обещание закрыть окно других пользователей или удалить зарегистрированный шрифт: экземпляр API сам по себе не снимает его описание из общего репозитория. При повторных запусках не рассчитывайте на автоматическое освобождение шрифтов. RemoveFont(font) удаляет описание из репозитория и при необходимости сбрасывает основной шрифт, но в этой реализации исходный нативный буфер намеренно не освобождается. Поэтому не добавляйте шрифт заново на каждом кадре и не используйте загрузку как бесконечный цикл смены шрифтов.
У методов загрузки шрифта нет аргумента CancellationToken: токен в примере удерживает выполнение скрипта до остановки, а не отменяет нативную загрузку. Совместимость TTF, пакета и нативного рендерера нужно проверять в своей установленной версии.

