Как отобразить специальные символы (₹,₤,₿..) в окне ImGui?

Я работаю над приложением, использующим ImGui для пользовательского интерфейса, и у меня возникли проблемы с отображением специальных символов, таких как символ индийской рупии (₹), в моих окнах ImGui. В настоящее время эти символы отображаются как ? вместо правильных символов. Я специально использую OpenGL в качестве основного средства визуализации.

Вот что я сделал на данный момент:

  1. Загружен шрифт: я обязательно загрузил шрифт, который должен поддерживать специальные символы.

  2. Функция замены: у меня есть функция, которая заменяет определенные строки-заполнители специальными символами.

У меня есть функция, которая заменяет определенные строки-заполнители специальными символами, включая символ индийской рупии. Вот функция:

  std::string replacedStr = str;
  std::map<std::string, std::string> replacements = {
    {"1397904493", "®"}, {"1397776754", "¶"}, {"1400073811", "§"},
    {"1396991858", "°"}, {"1396929140", "©"}, {"1398041963", "™"},
    {"1397059140", "–"}, {"1397058884", "—"}, {"1397969521", "’"},
    {"1397967985", "‘"}, {"1396986737", "\""}, {"1397969777", "'"},
    {"1397645907", " "}, {"1396984945", "“"}, {"1396986481", "”"},
    {"1396862068", "•"}, {"1397518451", "…"}, {"1398320179", "₹"}
  // Added mapping for the Indian Rupee symbol }; for (const auto &pair
  // : replacements) { size_t pos = replacedStr.find(pair.first); while
  // (pos != std::string::npos) { replacedStr.replace(pos,
  // pair.first.length(), pair.second); pos =
  // replacedStr.find(pair.first, pos + 1); } } return replacedStr; }

Я получаю следующий результат для некоторых специальных символов введите здесь описание изображения

здесь вы можете увидеть код методов преобразования и рендеринга

введите сюда описание изображения

или

for (size_t i = 0; i < contents.size();) {
 // Get the Unicode value of the current character and convert it to UTF-8
 uint32_t unicode = workose_studio_getUTF8Unicode(contents, i);
 std::string charStr = utf8::utf32to8(std::u32string(1, unicode));
 std::cout << " charStr :: " << charStr << " unicode :: " << unicode << std::endl;
 // Render the character
 draw_list->AddText(retrievedFont, retrievedFont->FontSize, adjusted_pen_pos, ImGui::GetColorU32(text_color), charStr.c_str(), NULL, 0.0f, NULL);
}

// Console output
// contents :: Char's : ₹ $ £ ¥ € ₠ ₡ ₤ ₥ ₦ ₧ ₨ ₩ ₪ ₫ € ₭ ₮ ₯ ₰ ₱ ₲ ₳ ₴ ₵ ₶ ₷ ₸ ₹ ₺ ₻ ₼ ₽ ₾ ₿
// charStr :: unicode :: 32
// charStr :: C unicode :: 67
// charStr :: h unicode :: 104
// charStr :: a unicode :: 97
// charStr :: r unicode :: 114
// charStr :: ' unicode :: 39
// charStr :: s unicode :: 115
// charStr :: unicode :: 32
// charStr :: : unicode :: 58
// charStr :: unicode :: 32
// charStr :: ₹ unicode :: 8377
// charStr :: unicode :: 32
// charStr :: $ unicode :: 36
// charStr :: unicode :: 32
// charStr :: £ unicode :: 163
// charStr :: unicode :: 32
// charStr :: ¥ unicode :: 165
// charStr :: unicode :: 32
// charStr :: € unicode :: 8364
// charStr :: unicode :: 32
// charStr :: ₠ unicode :: 8352
// charStr :: unicode :: 32
// charStr :: ₡ unicode :: 8353
// charStr :: unicode :: 32
// charStr :: ₤ unicode :: 8356
// charStr :: unicode :: 9
// charStr :: ₥ unicode :: 8357
// charStr :: unicode :: 32
// charStr :: ₦ unicode :: 8358
// charStr :: unicode :: 32
// charStr :: ₧ unicode :: 8359
// charStr :: unicode :: 9
// charStr :: ₨ unicode :: 8360
// charStr :: unicode :: 32
// charStr :: ₩ unicode :: 8361
// charStr :: unicode :: 32
// charStr :: ₪ unicode :: 8362
// charStr :: unicode :: 9
// charStr :: ₫ unicode :: 8363
// charStr :: unicode :: 32
// charStr :: € unicode :: 8364
// charStr :: unicode :: 32
// charStr :: ₭ unicode :: 8365
// charStr :: unicode :: 32
// charStr :: ₮ unicode :: 8366
// charStr :: unicode :: 32
// charStr :: ₯ unicode :: 8367
// charStr :: unicode :: 32
// charStr :: ₰ unicode :: 8368
// charStr :: unicode :: 32
// charStr :: ₱ unicode :: 8369
// charStr :: unicode :: 32
// charStr :: ₲ unicode :: 8370
// charStr :: unicode :: 32
// charStr :: ₳ unicode :: 8371
// charStr :: unicode :: 32
// charStr :: ₴ unicode :: 8372
// charStr :: unicode :: 32
// charStr :: ₵ unicode :: 8373
// charStr :: unicode :: 32
// charStr :: ₶ unicode :: 8374
// charStr :: unicode :: 32
// charStr :: ₷ unicode :: 8375

-------------------------------------- Код загрузки шрифта --------- ------------------------------

// Function to load fonts for ImGui in a custom application
void workose_studio_load_fonts()
{
   
    std::string defaultfont = workose_project_root_directory + "fonts/Roboto-Regular.ttf";

    // Get ImGui input/output configuration
    ImGuiIO &io = ImGui::GetIO();
    ImFontConfig config;

    // Get the default glyph range for the font
    const ImWchar *glyph_ranges = io.Fonts->GetGlyphRangesDefault();

    // Add the default font to ImGui with specified parameters
    ImFont *font = ImGui::GetIO().Fonts->AddFontFromFileTTF(
        defaultfont.c_str(),
        18,
        &config,
        glyph_ranges);

    // Store information about the default font
    workose_studio_font_data.font = font;
    workose_studio_font_data.path = defaultfont;

    // Map the default font information to the key "default"
    workose_studio_g_myFonts.fontMap["default"] = workose_studio_font_data;

    // Get the glyph range for Chinese characters
    const ImWchar *glyph_ranges1 = io.Fonts->GetGlyphRangesChineseFull();

    // Initialize an array to store font names
    std::vector<std::string> font_name;

    // Check if layout and element details are available
    if (workose_studio_get_layout_and_element_details.size() > 0)
    {
        // Iterate over layout elements
        for (nlohmann::json::iterator it = workose_studio_get_layout_and_element_details[0][0].begin(); it != workose_studio_get_layout_and_element_details[0][0].end(); ++it)
        {
            nlohmann::json layout_elements = it.value()["layout_elements"];

            // Iterate over layout element details
            for (nlohmann::json::iterator it = layout_elements.begin(); it != layout_elements.end(); ++it)
            {
                std::string element_type = it.value()["LAYOUT_ELEMENT_TYPE"];

                // Check if the element type is "text"
                if (element_type == "text")
                {
                    nlohmann::json paragraphs;
                    // Extract and decode element JSON style attributes
                    std::string element_json_style_attributes = it.value()["ELEMENT_JSON_STYLE_ATTRIBUTES"];
                    std::string decode_data = urldecode(element_json_style_attributes);
                    nlohmann::json json_data = nlohmann::json::parse(decode_data);

                    // Check for the presence of specific style attributes
                    if (json_data.find("frame_style") != json_data.end() && json_data["frame_style"].find("tableDetils") != json_data["frame_style"].end())
                    {

                        // Check if the "tableDetils" field is empty
                        if (json_data["frame_style"]["tableDetils"].empty())
                        {
                            nlohmann::json decoded_json = nlohmann::json::parse(decode_data);
                            // Check for the presence of "paragraphs" in the decoded JSON
                            if (decoded_json.contains("paragraphs"))
                            {
                                paragraphs = decoded_json["paragraphs"];
                                // Store used fonts from paragraphs
                                storeusedfonts(paragraphs);
                            }
                        }
                        else
                        {
                            // table condition
                            const nlohmann::json &frame_style = json_data["frame_style"];
                            // Check for the presence of "tableDetils" in "frame_style"
                            if (frame_style.contains("tableDetils"))
                            {
                                const nlohmann::json &table_details = frame_style["tableDetils"];
                                // Check for the presence of "tableContentArray" in "tableDetils"
                                if (table_details.contains("tableContentArray"))
                                {
                                    const nlohmann::json &table_content_array = table_details["tableContentArray"];
                                    size_t numColumns = table_content_array[std::to_string(0)].size();

                                    // Iterate over table columns and rows
                                    for (size_t x = 0; x < numColumns; ++x)
                                    {
                                        for (size_t j = 0; j < table_content_array.size(); ++j)
                                        {
                                            const nlohmann::json &row_j = table_content_array[std::to_string(j)];

                                            // Check for the presence of the current column in the current row
                                            if (row_j.contains(std::to_string(x)))
                                            {
                                                const nlohmann::json &cell_ij = row_j[std::to_string(x)];

                                                // Check for the presence of "style" in the cell
                                                if (cell_ij.contains("style"))
                                                {
                                                    const nlohmann::json &styleObj = cell_ij["style"];

                                                    // Check for the presence of "paragraphs" in the style
                                                    if (styleObj.contains("paragraphs"))
                                                    {
                                                        paragraphs = styleObj["paragraphs"];
                                                        // Store used fonts from paragraphs
                                                        storeusedfonts(paragraphs);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Похоже, ваш шрифт не поддерживает эти символы. Однако трудно сказать без минимального воспроизводимого примера .

n. m. could be an AI 23.05.2024 06:01

@n.m.couldbeanAI я использовал шрифт Arial, он поддерживает символ индийской рупии (₹)

vinith 23.05.2024 06:53

MRE до сих пор нет, поэтому выявить проблему не стало легче.

n. m. could be an AI 23.05.2024 07:02

При этом все ваши символы, которые отображаются правильно, принадлежат к кодировке CP-1252 (и Latin-1), поэтому, возможно, ваша программа в какой-то момент не использует UTF-8.

n. m. could be an AI 23.05.2024 07:39

Ваши строки закодированы в utf-8? Какой компилятор вы используете? Какая у вас командная строка компилятора?

Alan Birtles 23.05.2024 07:42

При загрузке шрифта можно указать какие символы загружать, а вы там видимо не свои указываете. Кроме того, сама идея замены строки странная: просто используйте \u20B9 (или \xE2\x82\xB9) для символа рупии и так далее.

HolyBlackCat 23.05.2024 08:51

@n.m.couldbeanAI, как вы видите на изображении, которое я прикрепил, я получаю символ и его значение в Юникоде после преобразования в utf-8

vinith 23.05.2024 08:52

@AlanBirtles Конечно, в кодировке utf-8, как вы видите на изображении, которое я сейчас прикрепил, и я использую компилятор clang.

vinith 23.05.2024 08:54

Пожалуйста, не размещайте изображения текста. Я не уверен, как на изображении видно, что строки имеют кодировку utf8?

Alan Birtles 23.05.2024 08:56

Пожалуйста, не публикуйте изображения кода. Они хуже, чем бесполезны. Вместо этого опубликуйте минимально воспроизводимый пример . Пожалуйста, обратите внимание на минимальные требования. Замены текста не имеют значения, поэтому не включайте их в свой минимально воспроизводимый пример. Вместо этого укажите почтовый код, который открывает пользовательский интерфейс и отображает одну строку. Больше ничего.

n. m. could be an AI 23.05.2024 09:03

@n.m.couldbeanAI программа нигде не использует UTF8. Тип строки UTF8 — std::utf8string, а не std::string. std::string может вести себя как UTF8, если кодовая страница ОС явно установлена ​​в UTF8.

Panagiotis Kanavos 23.05.2024 09:08

@vinith, какую ОС вы используете и какую кодировку использовали при сохранении файла? Windows, например, изначально использует Unicode с середины 1990-х годов, а точнее, UTF16, хотя в прошлом использовалось только подмножество UCS-2, для которого всегда требуется 2 байта. UTF16 может использовать более 2 байтов. Типы строк в Юникоде: std::u16string, а в последнее время и std::u8string. Вы также найдете устаревший код, в котором используется std::wstring. Литералам Юникода требуется префикс, например `auto x=u"₹"; для UTF16.

Panagiotis Kanavos 23.05.2024 09:10

@AlanBirtles ок, я заменил изображение кодом на функцию, конвертирующую utf 32 в utf8

vinith 23.05.2024 09:11

@PanagiotisKanavos *изначально UTF-16

Botje 23.05.2024 09:12

@PanagiotisKanavos Mac OS

vinith 23.05.2024 09:16

@vinith Пожалуйста, отредактируйте свой вопрос, указав код, который загружает шрифт, так как в разделе часто задаваемых вопросов объясняется, что вы должны указать, какие диапазоны глифов загружаются

Botje 23.05.2024 09:20

@PanagiotisKanavos Использование std::utf8string не гарантирует правильное отображение строк UTF8. Это контейнер char8_t, не более того. В char8_t нет ничего магического, это просто еще один 8-битный тип символов. Это необходимо только для разрешения перегрузки. Как только вы передадите группу char8_t во внешнюю библиотеку, она будет неотличима от любой другой группы байтов.

n. m. could be an AI 23.05.2024 09:23

@vinith converting utf 32 to utf8 в вашем коде нет строк UTF32. Здесь нет литералов u32string, char32_t или U"xxx", поэтому все они представляют собой просто однобайтовые символы. Стандартный способ конвертации — использование codecvt . Обходной путь — использовать функции ОС. Вероятно, вам следует проверить, какие фактические стандартные типы строк

Panagiotis Kanavos 23.05.2024 09:24

@n.m.couldbeanAI не использует правильный тип, хотя гарантирует моджибаке или, что еще хуже, потерю данных. В этом случае будет потерян, потому что его нет в Latin1. Дальше дело за ОС (я вообще-то помню переход на операционки с Unicode). Windows и MacOS не будут иметь никаких проблем с приложениями с графическим интерфейсом. В терминалах для самого терминала должна быть установлена ​​правильная кодовая страница либо через chcp, настройки терминала, LC_ALL, LANG или настройки ОС.

Panagiotis Kanavos 23.05.2024 09:25

@n.m.couldbeanAI Я помню один проблемный MacBook 7 лет назад, где ОС и iTerm2 имели разные настройки LC_ALL. Ребятам из ИТ-поддержки потребовалось некоторое время, чтобы понять, почему приложения с графическим интерфейсом работают, но терминал и iTerm искажали текст по-разному.

Panagiotis Kanavos 23.05.2024 09:29

@Botje, я включил код загрузки шрифта

vinith 23.05.2024 10:58

@PanagiotisKanavos «не использует правильный тип, хотя и гарантирует» IME, что правильный тип для хранения данных UTF-8 — std::string. Нет необходимости использовать char8_t или std::u8string. Проблема ОП связана со шрифтами imgui. Диапазон глифов по умолчанию не содержит необходимых символов. Им нужно загрузить пользовательский диапазон, вот и все. (Замена текста тоже выглядит как проблема, но на другом уровне, не связанном с рендерингом глифов)

n. m. could be an AI 23.05.2024 11:19

@n.m.couldbeanAI Apple, Microsoft и сообщества C и C++ не согласны с вами, поэтому у нас есть многоязычные настольные ОС, которые могут без проблем работать одновременно с немецким и кириллическим текстом. Не говоря уже о сотнях вопросов SO, вызванных двусмысленностью между UTF8 и char/string. Единственное, что вы можете сказать, это то, что комитету C++ потребовалось слишком много времени, чтобы стандартизировать UTF8, и слишком долго, чтобы перейти только к UTF16.

Panagiotis Kanavos 23.05.2024 11:27

@PanagiotisKanavos «именно поэтому у нас есть многоязычные настольные ОС» Еще в начале 2000-х в моем распоряжении была многоязычная настольная ОС (на самом деле более одной), которая могла без проблем работать с немецким и кириллическим текстом одновременно. Это было задолго до того, как std::u8string был задуман.

n. m. could be an AI 23.05.2024 12:07

@PanagiotisKanavos Я не вижу много вопросов ТАК, на которые можно было бы разумно ответить, «просто используйте std::u8string вместо std::string». Ты? Можете ли вы показать мне один?

n. m. could be an AI 23.05.2024 12:07

@PanagiotisKanavos «комитету потребовалось слишком много времени, чтобы стандартизировать UTF8» О, но стандартизировал ли он когда-нибудь UTF8? std::cout << std::u8string(u8"Hello"); подходит вам? Что этот тип решает еще раз? Где мне нужно будет его использовать?

n. m. could be an AI 23.05.2024 12:13

В приложениях, которым необходимо читать два файла с двумя разными кодовыми страницами, чтобы они не могли зависеть от внешней кодовой страницы. Я не случайно использовал немецкий и кириллицу. Было несколько вопросов R (которые использовали std::string в Linux) от немецких специалистов по обработке данных, которые спрашивали, почему они не могут загрузить польские и русские файлы данных вместе со своими собственными. Наличие определенных типов Юникода предотвращает такие путаницы.

Panagiotis Kanavos 23.05.2024 12:54

@PanagiotisKanavos Это не считается. Как наличие определенного типа Unicode предотвращает путаницу типов, не поддерживающих Unicode? Если у вас есть тип UTF-8 и вы конвертируете все, что вы читаете из файлов, в этот тип, вы предотвращаете путаницу, потому что все в вашей программе — UTF-8. Но тогда не имеет значения, какой тип вы используете. Мы использовали char и std::string для этой цели задолго до i8string. Это наши де-факто типы UTF-8. Если R не сохраняет все внутри UTF-8, вините в этом R. Sane языки, и им для этого не нужен std::u8string.

n. m. could be an AI 23.05.2024 13:27
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
28
284
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Знак рупии (U+20B9) не входит в диапазон глифов ImGui по умолчанию или китайский диапазон. Вам необходимо создать собственный диапазон глифов (просто пары кодовых точек начала и остановки) и указать его при загрузке шрифта. То же самое и с другими отсутствующими глифами.

В разделе FAQ приведены следующие примеры:

ImVector<ImWchar> ranges;
ImFontGlyphRangesBuilder builder;
builder.AddText("Hello world");                        // Add a string (here "Hello world" contains 7 unique characters)
builder.AddChar(0x20B9);                               // Add a specific character
builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges
builder.BuildRanges(&ranges);                          // Build the final result (ordered ranges with all the unique characters submitted)
io.Fonts->AddFontFromFileTTF("myfontfile.ttf", 16.0f, nullptr, ranges.Data);

Другие вопросы по теме