Я работаю над приложением, использующим ImGui для пользовательского интерфейса, и у меня возникли проблемы с отображением специальных символов, таких как символ индийской рупии (₹), в моих окнах ImGui. В настоящее время эти символы отображаются как ? вместо правильных символов. Я специально использую OpenGL в качестве основного средства визуализации.
Вот что я сделал на данный момент:
Загружен шрифт: я обязательно загрузил шрифт, который должен поддерживать специальные символы.
Функция замены: у меня есть функция, которая заменяет определенные строки-заполнители специальными символами.
У меня есть функция, которая заменяет определенные строки-заполнители специальными символами, включая символ индийской рупии. Вот функция:
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.couldbeanAI я использовал шрифт Arial, он поддерживает символ индийской рупии (₹)
MRE до сих пор нет, поэтому выявить проблему не стало легче.
При этом все ваши символы, которые отображаются правильно, принадлежат к кодировке CP-1252 (и Latin-1), поэтому, возможно, ваша программа в какой-то момент не использует UTF-8.
Ваши строки закодированы в utf-8? Какой компилятор вы используете? Какая у вас командная строка компилятора?
При загрузке шрифта можно указать какие символы загружать, а вы там видимо не свои указываете. Кроме того, сама идея замены строки странная: просто используйте \u20B9 (или \xE2\x82\xB9) для символа рупии и так далее.
@n.m.couldbeanAI, как вы видите на изображении, которое я прикрепил, я получаю символ и его значение в Юникоде после преобразования в utf-8
@AlanBirtles Конечно, в кодировке utf-8, как вы видите на изображении, которое я сейчас прикрепил, и я использую компилятор clang.
Пожалуйста, не размещайте изображения текста. Я не уверен, как на изображении видно, что строки имеют кодировку utf8?
Пожалуйста, не публикуйте изображения кода. Они хуже, чем бесполезны. Вместо этого опубликуйте минимально воспроизводимый пример . Пожалуйста, обратите внимание на минимальные требования. Замены текста не имеют значения, поэтому не включайте их в свой минимально воспроизводимый пример. Вместо этого укажите почтовый код, который открывает пользовательский интерфейс и отображает одну строку. Больше ничего.
@n.m.couldbeanAI программа нигде не использует UTF8. Тип строки UTF8 — std::utf8string, а не std::string. std::string может вести себя как UTF8, если кодовая страница ОС явно установлена в UTF8.
@vinith, какую ОС вы используете и какую кодировку использовали при сохранении файла? Windows, например, изначально использует Unicode с середины 1990-х годов, а точнее, UTF16, хотя в прошлом использовалось только подмножество UCS-2, для которого всегда требуется 2 байта. UTF16 может использовать более 2 байтов. Типы строк в Юникоде: std::u16string, а в последнее время и std::u8string. Вы также найдете устаревший код, в котором используется std::wstring. Литералам Юникода требуется префикс, например `auto x=u"₹"; для UTF16.
@AlanBirtles ок, я заменил изображение кодом на функцию, конвертирующую utf 32 в utf8
@PanagiotisKanavos *изначально UTF-16
@PanagiotisKanavos Mac OS
@vinith Пожалуйста, отредактируйте свой вопрос, указав код, который загружает шрифт, так как в разделе часто задаваемых вопросов объясняется, что вы должны указать, какие диапазоны глифов загружаются
@PanagiotisKanavos Использование std::utf8string не гарантирует правильное отображение строк UTF8. Это контейнер char8_t, не более того. В char8_t нет ничего магического, это просто еще один 8-битный тип символов. Это необходимо только для разрешения перегрузки. Как только вы передадите группу char8_t во внешнюю библиотеку, она будет неотличима от любой другой группы байтов.
@vinith converting utf 32 to utf8 в вашем коде нет строк UTF32. Здесь нет литералов u32string, char32_t или U"xxx", поэтому все они представляют собой просто однобайтовые символы. Стандартный способ конвертации — использование codecvt . Обходной путь — использовать функции ОС. Вероятно, вам следует проверить, какие фактические стандартные типы строк
@n.m.couldbeanAI не использует правильный тип, хотя гарантирует моджибаке или, что еще хуже, потерю данных. В этом случае ₹ будет потерян, потому что его нет в Latin1. Дальше дело за ОС (я вообще-то помню переход на операционки с Unicode). Windows и MacOS не будут иметь никаких проблем с приложениями с графическим интерфейсом. В терминалах для самого терминала должна быть установлена правильная кодовая страница либо через chcp, настройки терминала, LC_ALL, LANG или настройки ОС.
@n.m.couldbeanAI Я помню один проблемный MacBook 7 лет назад, где ОС и iTerm2 имели разные настройки LC_ALL. Ребятам из ИТ-поддержки потребовалось некоторое время, чтобы понять, почему приложения с графическим интерфейсом работают, но терминал и iTerm искажали текст по-разному.
@Botje, я включил код загрузки шрифта
@PanagiotisKanavos «не использует правильный тип, хотя и гарантирует» IME, что правильный тип для хранения данных UTF-8 — std::string. Нет необходимости использовать char8_t или std::u8string. Проблема ОП связана со шрифтами imgui. Диапазон глифов по умолчанию не содержит необходимых символов. Им нужно загрузить пользовательский диапазон, вот и все. (Замена текста тоже выглядит как проблема, но на другом уровне, не связанном с рендерингом глифов)
@n.m.couldbeanAI Apple, Microsoft и сообщества C и C++ не согласны с вами, поэтому у нас есть многоязычные настольные ОС, которые могут без проблем работать одновременно с немецким и кириллическим текстом. Не говоря уже о сотнях вопросов SO, вызванных двусмысленностью между UTF8 и char/string. Единственное, что вы можете сказать, это то, что комитету C++ потребовалось слишком много времени, чтобы стандартизировать UTF8, и слишком долго, чтобы перейти только к UTF16.
@PanagiotisKanavos «именно поэтому у нас есть многоязычные настольные ОС» Еще в начале 2000-х в моем распоряжении была многоязычная настольная ОС (на самом деле более одной), которая могла без проблем работать с немецким и кириллическим текстом одновременно. Это было задолго до того, как std::u8string был задуман.
@PanagiotisKanavos Я не вижу много вопросов ТАК, на которые можно было бы разумно ответить, «просто используйте std::u8string вместо std::string». Ты? Можете ли вы показать мне один?
@PanagiotisKanavos «комитету потребовалось слишком много времени, чтобы стандартизировать UTF8» О, но стандартизировал ли он когда-нибудь UTF8? std::cout << std::u8string(u8"Hello"); подходит вам? Что этот тип решает еще раз? Где мне нужно будет его использовать?
В приложениях, которым необходимо читать два файла с двумя разными кодовыми страницами, чтобы они не могли зависеть от внешней кодовой страницы. Я не случайно использовал немецкий и кириллицу. Было несколько вопросов R (которые использовали std::string в Linux) от немецких специалистов по обработке данных, которые спрашивали, почему они не могут загрузить польские и русские файлы данных вместе со своими собственными. Наличие определенных типов Юникода предотвращает такие путаницы.
@PanagiotisKanavos Это не считается. Как наличие определенного типа Unicode предотвращает путаницу типов, не поддерживающих Unicode? Если у вас есть тип UTF-8 и вы конвертируете все, что вы читаете из файлов, в этот тип, вы предотвращаете путаницу, потому что все в вашей программе — UTF-8. Но тогда не имеет значения, какой тип вы используете. Мы использовали char и std::string для этой цели задолго до i8string. Это наши де-факто типы UTF-8. Если R не сохраняет все внутри UTF-8, вините в этом R. Sane языки, и им для этого не нужен std::u8string.





Знак рупии (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);
Похоже, ваш шрифт не поддерживает эти символы. Однако трудно сказать без минимального воспроизводимого примера .