From d46ebd32fd957b1e4d7b041f96a08856f2e83fec Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Sat, 14 Mar 2026 23:47:07 +0300 Subject: [PATCH 1/3] font: add multi-font support this checks for an array at `defaults.fonts`, and loads each element as a string, skipping any non-strings on the way. when it comes to loading the font for imgui, it loads each font, and sets the first successfully-loaded font as the default. when it comes to anywhere else, the first element is treated as the default. support for `default.font` also works, and it's treated as the least-priority font. --- include/config.hpp | 26 ++++++++++++++------------ src/config.cpp | 34 +++++++++++++++++++++++++++++++++- src/main_tool_opengl3.cpp | 13 ++++++++----- src/screenshot_tool.cpp | 2 +- 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/include/config.hpp b/include/config.hpp index e5bf11e..17dd7e9 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -37,15 +37,15 @@ class Config // They can be overwritten from CLI arguments struct config_file_t { - std::string ocr_path; - std::string ocr_model; - std::string font; - int delay = -1; - bool allow_out_edit = false; - bool real_full_screen = false; - bool show_text_tools = true; - bool enable_vsync = true; - bool render_anns = true; + std::string ocr_path; + std::string ocr_model; + std::vector fonts; + int delay = -1; + bool allow_out_edit = false; + bool real_full_screen = false; + bool show_text_tools = true; + bool enable_vsync = true; + bool render_anns = true; } File; // Only from CLI arguments @@ -190,9 +190,11 @@ show-text-tools = true # or only when saving the selection (false) annotations-in-text-tools = true -# Default font (absolute path or just name) for the whole application. -# Leave/Make it empty, or commment it, to use ImGUI default font. -font = "Arial.ttf" +# Fonts to use for the application. Can be an absolute path, or just a name. +# You can combine multiple fonts for multiple language support. +# for example, using `Roboto-Regular.ttf` and `RobotoCJK-Regular.ttc` for Chinese, Japanese, and Korean support alongside English support. +# If empty, or non-existent (commented out), oshot will use the default font for ImGUI. +fonts = ["Arial.ttf"] )#"; inline constexpr std::string_view oshot_help = (R"(Usage: oshot [OPTIONS]... diff --git a/src/config.cpp b/src/config.cpp index 84008cf..ba0e3a4 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -42,9 +42,41 @@ void Config::LoadConfigFile(const std::string& filename) err.source().begin.column); } + // Fonts + auto fonts = m_tbl.at_path("default.fonts"); + if (fonts.is_array()) + { + toml::array* font_arr = fonts.as_array(); + if (font_arr) + { + File.fonts.reserve(font_arr->size()); + + size_t idx = 0; + for (auto&& font : *font_arr) + { + std::optional font_opt = font.value(); + + if (!font_opt.has_value()) + { + warn("Font at index {} is not a string!", idx); + idx++; + continue; + } + + File.fonts.push_back(font_opt.value()); + idx++; + } + } + } + + auto font = m_tbl.at_path("default.font").value(); + if (font.has_value()) + { + File.fonts.push_back(font.value()); + } + File.ocr_path = GetValue("default.ocr-path", "/usr/share/tessdata"); File.ocr_model = GetValue("default.ocr-model", "eng"); - File.font = GetValue("default.font", ""); File.delay = GetValue("default.delay", -1); File.show_text_tools = GetValue("default.show-text-tools", true); File.enable_vsync = GetValue("default.vsync", true); diff --git a/src/main_tool_opengl3.cpp b/src/main_tool_opengl3.cpp index 6b0318f..15498b1 100644 --- a/src/main_tool_opengl3.cpp +++ b/src/main_tool_opengl3.cpp @@ -211,12 +211,15 @@ int run_main_tool(const std::string& imgui_ini_path) io.IniFilename = imgui_ini_path.c_str(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - if (!g_config->File.font.empty()) + for (const std::string& font : g_config->File.fonts) { - const fs::path& path = get_font_path(g_config->File.font); - if (fs::exists(path)) - io.FontDefault = - io.Fonts->AddFontFromFileTTF(path.string().c_str(), 16.0f, nullptr, io.Fonts->GetGlyphRangesDefault()); + const fs::path& path = get_font_path(font); + ImFont* loaded_font = + io.Fonts->AddFontFromFileTTF(path.string().c_str(), 16.0f, nullptr, io.Fonts->GetGlyphRangesDefault()); + + // First successfully loaded font will remain the default. + if (!io.FontDefault) + io.FontDefault = loaded_font; } // Setup Platform/Renderer backends diff --git a/src/screenshot_tool.cpp b/src/screenshot_tool.cpp index 32b394e..b037568 100644 --- a/src/screenshot_tool.cpp +++ b/src/screenshot_tool.cpp @@ -238,7 +238,7 @@ Result<> ScreenshotTool::StartWindow() m_io = ImGui::GetIO(); m_state = ToolState::Selecting; - m_inputs.ann_font = g_config->File.font; + m_inputs.ann_font = g_config->File.fonts.size() > 0 ? g_config->File.fonts[0] : ""; m_show_text_tools = g_config->File.show_text_tools; fit_to_screen(m_screenshot); From 754817d5a24509ac6da2b97b4f3c29ba9642acc5 Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Sun, 15 Mar 2026 00:23:27 +0300 Subject: [PATCH 2/3] imgui: merge font glyphs --- src/main_tool_opengl3.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main_tool_opengl3.cpp b/src/main_tool_opengl3.cpp index 15498b1..e73e0cb 100644 --- a/src/main_tool_opengl3.cpp +++ b/src/main_tool_opengl3.cpp @@ -211,21 +211,23 @@ int run_main_tool(const std::string& imgui_ini_path) io.IniFilename = imgui_ini_path.c_str(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + // Setup Platform/Renderer backends + ImGui_ImplGlfw_InitForOpenGL(window, true); + ImGui_ImplOpenGL3_Init(glsl_version); + + ImFontConfig font_cfg; + for (const std::string& font : g_config->File.fonts) { const fs::path& path = get_font_path(font); - ImFont* loaded_font = - io.Fonts->AddFontFromFileTTF(path.string().c_str(), 16.0f, nullptr, io.Fonts->GetGlyphRangesDefault()); + io.Fonts->AddFontFromFileTTF(path.string().c_str(), 16.0f, &font_cfg); - // First successfully loaded font will remain the default. - if (!io.FontDefault) - io.FontDefault = loaded_font; + // this value is false by default, and we can't set it to true without adding atleast one font first. + // so, after we add the first font, this will be true (and will stay true). + // MergeMode fills the gap in previous fonts with glyphs from this font, for example, adding Arabic glyphs to a non-Arabic font. + font_cfg.MergeMode = true; } - // Setup Platform/Renderer backends - ImGui_ImplGlfw_InitForOpenGL(window, true); - ImGui_ImplOpenGL3_Init(glsl_version); - { const Result<>& res = ss_tool.StartWindow(); if (!res.ok()) From 9bf79f972f4824838352b4b291c187bbd669cb61 Mon Sep 17 00:00:00 2001 From: BurntRanch Date: Sun, 15 Mar 2026 00:24:46 +0300 Subject: [PATCH 3/3] fonts: add support for Metal tool --- src/main_tool_metal.mm | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main_tool_metal.mm b/src/main_tool_metal.mm index 41253cd..202e5c4 100644 --- a/src/main_tool_metal.mm +++ b/src/main_tool_metal.mm @@ -172,17 +172,22 @@ int run_main_tool(const std::string& imgui_ini_path) io.IniFilename = imgui_ini_path.c_str(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - if (!g_config->File.font.empty()) - { - const auto& path = get_font_path(g_config->File.font); - if (!path.empty()) - io.FontDefault = - io.Fonts->AddFontFromFileTTF(path.string().c_str(), 16.0f, nullptr, io.Fonts->GetGlyphRangesDefault()); - } - ImGui_ImplGlfw_InitForOther(window, true); // "Other" = non-GL backend ImGui_ImplMetal_Init(device); + ImFontConfig font_cfg; + + for (const std::string& font : g_config->File.fonts) + { + const fs::path& path = get_font_path(font); + io.Fonts->AddFontFromFileTTF(path.string().c_str(), 16.0f, &font_cfg); + + // this value is false by default, and we can't set it to true without adding atleast one font first. + // so, after we add the first font, this will be true (and will stay true). + // MergeMode fills the gap in previous fonts with glyphs from this font, for example, adding Arabic glyphs to a non-Arabic font. + font_cfg.MergeMode = true; + } + { const Result<>& res = ss_tool.StartWindow(); if (!res.ok())