From 84330d50697688abf97128c8fc110b62129cfb31 Mon Sep 17 00:00:00 2001 From: Nanako <469449812@qq.com> Date: Tue, 8 Apr 2025 01:17:51 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A2=9C=E8=89=B2=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/src/main.cpp | 32 +++- src/mirage_image/color.cpp | 375 +++++++++++++++++++++++-------------- 2 files changed, 260 insertions(+), 147 deletions(-) diff --git a/example/src/main.cpp b/example/src/main.cpp index f2583e7..5d77a07 100644 --- a/example/src/main.cpp +++ b/example/src/main.cpp @@ -20,6 +20,34 @@ int main(int argc, char* argv[]) { auto description = mirage_style::get().description(); auto license = mirage_style::get().license(); + const char* test_cases[] = { + "#FFF", // hex rgb + "#ff0000", // hex RRGGBB + "#00ff0080", // hex RRGGBBAA + "#1234", // hex RGBA + "rgb(255,0,0)", // rgb int + "rgba(0,255,0,128)",// rgba int + "rgba(0, 0, 255, 255)", // rgba int with spaces + "rgb(1.0, 0.0, 0.0)", // rgb float + "rgba(0.0, 1.0, 0.0, 0.5)",// rgba float + " rgb(0.0, 0.0, 1.0) ", // rgb float with spaces + "rgba(1, 0.5, 0, 1.0)", // rgba mixed - should parse as float + "invalid", + "#12345", + "rgb(300,0,0)", + "rgba(1.1, 0, 0, 1)", + "rgba(100,100,100)" // missing alpha + }; + + for (const char* test_str : test_cases) { + std::optional color = linear_color::from_string(test_str); + std::cout << "Parsing '" << test_str << "': "; + if (color) { + std::cout << "Success -> r:" << color->r << " g:" << color->g << " b:" << color->b << " a:" << color->a << std::endl; + } else { + std::cout << "Failed" << std::endl; + } + } auto& manager = font_manager::instance(); manager.add_font(L"C:/Users/46944/AppData/Local/Microsoft/Windows/Fonts/MapleMono-NF-CN-Regular.ttf"); @@ -36,10 +64,8 @@ int main(int argc, char* argv[]) { ss << "license: " << license << "\n"; // text_block->set_text(U"Hello, World! 你好,世界!\n换行测试1111,测试测试测试测试,测试测试😀🐵🙏 😃🐵🙏"); - const auto& utf32 = utf8::utf8to32(ss.str()); - // const char*转换为std::u32string - text_block->set_text(utf32); + text_block->set_text(utf8::utf8to32(ss.str())); const auto& text_block2 = std::make_shared(); text_block2->set_text(U"Hello, World!"); diff --git a/src/mirage_image/color.cpp b/src/mirage_image/color.cpp index ded65db..1198af0 100644 --- a/src/mirage_image/color.cpp +++ b/src/mirage_image/color.cpp @@ -1,155 +1,242 @@ #include "color.h" -/** - * @brief 将十六进制字符转换为整数值 - * - * @param hex 十六进制字符 (0-9, A-F, a-f) - * @return 对应的整数值 (0-15),如果字符无效则返回-1 - */ -int hex_char_to_int(char hex) { - if (hex >= '0' && hex <= '9') - return hex - '0'; - if (hex >= 'A' && hex <= 'F') - return hex - 'A' + 10; - if (hex >= 'a' && hex <= 'f') - return hex - 'a' + 10; - return -1; // 无效字符 +#include +#include +#include + +// --- 辅助函数 --- + +// 将单个十六进制字符转换为整数 (0-15) +int hex_char_to_int(char c) { + if (c >= '0' && c <= '9') { + return c - '0'; + } + if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } + if (c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } + return -1; } -std::optional linear_color::from_string(const std::string& in_str) { +// 去除字符串首尾空格 +std::string trim_whitespace(const std::string& str) { + size_t first = str.find_first_not_of(" \t\n\r\f\v"); + if (std::string::npos == first) { + return str; // String contains only whitespace + } + size_t last = str.find_last_not_of(" \t\n\r\f\v"); + return str.substr(first, (last - first + 1)); +} + +// 按分隔符分割字符串 +std::vector split_string(const std::string& str, char delimiter) { + std::vector tokens; + std::string token; + std::istringstream tokenStream(str); + while (std::getline(tokenStream, token, delimiter)) { + tokens.push_back(token); + } + return tokens; +} + + +// --- 十六进制格式解析辅助函数 (保持不变) --- +std::optional parse_hex_color(const std::string& in_str) { + const auto& hex_part = in_str.substr(1); + const size_t length = hex_part.length(); + + // 检查所有字符是否为有效十六进制数字 (使用 cctype::isxdigit) + for (const char c: hex_part) { + if (!::isxdigit(static_cast(c))) { return std::nullopt; } + } + linear_color result{}; - // 处理十六进制格式 - if (!in_str.empty() && in_str[0] == '#') { - // **支持的十六进制格式:** #RGB, #RGBA, #RRGGBB, #RRGGBBAA - size_t length = in_str.length(); - - // 检查格式并解析 - if (length == 4) { // #RGB 格式 - // 检查所有字符是否都是有效的十六进制数字 - for (int i = 1; i < 4; i++) { - if (!std::isxdigit(in_str[i])) - return std::nullopt; - } - - // 对于 #RGB 格式,每个字符需要重复:R -> RR, G -> GG, B -> BB - int r = hex_char_to_int(in_str[1]); - int g = hex_char_to_int(in_str[2]); - int b = hex_char_to_int(in_str[3]); - - // 将 0-15 的值扩展到 0-255 的范围 - result.r = (r * 16 + r) / 255.0f; - result.g = (g * 16 + g) / 255.0f; - result.b = (b * 16 + b) / 255.0f; - result.a = 1.0f; // 默认为完全不透明 - - return result; - } - if (length == 5) { // #RGBA 格式 - // 检查所有字符是否都是有效的十六进制数字 - for (int i = 1; i < 5; i++) { - if (!std::isxdigit(in_str[i])) - return std::nullopt; - } - - int r = hex_char_to_int(in_str[1]); - int g = hex_char_to_int(in_str[2]); - int b = hex_char_to_int(in_str[3]); - int a = hex_char_to_int(in_str[4]); - - // 将 0-15 的值扩展到 0-255 的范围 - result.r = (r * 16 + r) / 255.0f; - result.g = (g * 16 + g) / 255.0f; - result.b = (b * 16 + b) / 255.0f; - result.a = (a * 16 + a) / 255.0f; - - return result; - } - if (length == 7) { // #RRGGBB 格式 - // 检查所有字符是否都是有效的十六进制数字 - for (int i = 1; i < 7; i++) { - if (!std::isxdigit(in_str[i])) - return std::nullopt; - } - - int r = (hex_char_to_int(in_str[1]) << 4) + hex_char_to_int(in_str[2]); - int g = (hex_char_to_int(in_str[3]) << 4) + hex_char_to_int(in_str[4]); - int b = (hex_char_to_int(in_str[5]) << 4) + hex_char_to_int(in_str[6]); - - result.r = r / 255.0f; - result.g = g / 255.0f; - result.b = b / 255.0f; - result.a = 1.0f; // 默认为完全不透明 - - return result; - } - if (length == 9) { // #RRGGBBAA 格式 - // 检查所有字符是否都是有效的十六进制数字 - for (int i = 1; i < 9; i++) { - if (!std::isxdigit(in_str[i])) - return std::nullopt; - } - - int r = (hex_char_to_int(in_str[1]) << 4) + hex_char_to_int(in_str[2]); - int g = (hex_char_to_int(in_str[3]) << 4) + hex_char_to_int(in_str[4]); - int b = (hex_char_to_int(in_str[5]) << 4) + hex_char_to_int(in_str[6]); - int a = (hex_char_to_int(in_str[7]) << 4) + hex_char_to_int(in_str[8]); - - result.r = r / 255.0f; - result.g = g / 255.0f; - result.b = b / 255.0f; - result.a = a / 255.0f; - - return result; - } - // 无效的十六进制格式长度 - return std::nullopt; - } - - // 如果不是十六进制格式,继续处理 RGB/RGBA 格式 - int r_int, g_int, b_int, a_int = 255; // Alpha 默认值为 255 (对应 1.0f) - int components_read = 0; - char closing_paren = '\0'; - - // 尝试匹配 rgba(r,g,b,a) 格式 - components_read = std::sscanf(in_str.c_str(), "rgba(%d,%d,%d,%d %c", - &r_int, &g_int, &b_int, &a_int, &closing_paren); - - if (components_read == 5 && closing_paren == ')') { - // 验证数值范围 [0, 255] - if (r_int < 0 || r_int > 255 || g_int < 0 || g_int > 255 || - b_int < 0 || b_int > 255 || a_int < 0 || a_int > 255) { - return std::nullopt; // 数值超出范围 - } - - // 归一化到 [0.0, 1.0] - result.r = static_cast(r_int) / 255.0f; - result.g = static_cast(g_int) / 255.0f; - result.b = static_cast(b_int) / 255.0f; - result.a = static_cast(a_int) / 255.0f; - return result; - } - - // 如果 RGBA 格式不匹配,尝试匹配 rgb(r,g,b) 格式 - closing_paren = '\0'; // 重置 - components_read = std::sscanf(in_str.c_str(), "rgb(%d,%d,%d %c", - &r_int, &g_int, &b_int, &closing_paren); - - if (components_read == 4 && closing_paren == ')') { - // 验证数值范围 [0, 255] - if (r_int < 0 || r_int > 255 || g_int < 0 || g_int > 255 || - b_int < 0 || b_int > 255) { - return std::nullopt; // 数值超出范围 - } - - // 归一化到 [0.0, 1.0],Alpha 使用默认值 1.0f - result.r = static_cast(r_int) / 255.0f; - result.g = static_cast(g_int) / 255.0f; - result.b = static_cast(b_int) / 255.0f; + // #RGB + if (length == 3) { + int r = hex_char_to_int(hex_part[0]); + int g = hex_char_to_int(hex_part[1]); + int b = hex_char_to_int(hex_part[2]); + if (r == -1 || g == -1 || b == -1) + return std::nullopt; + result.r = (r * 16 + r) / 255.0f; + result.g = (g * 16 + g) / 255.0f; + result.b = (b * 16 + b) / 255.0f; result.a = 1.0f; return result; } - - // 所有格式都不匹配 + // #RGBA + if (length == 4) { + int r = hex_char_to_int(hex_part[0]); + int g = hex_char_to_int(hex_part[1]); + int b = hex_char_to_int(hex_part[2]); + int a = hex_char_to_int(hex_part[3]); + if (r == -1 || g == -1 || b == -1 || a == -1) + return std::nullopt; + result.r = (r * 16 + r) / 255.0f; + result.g = (g * 16 + g) / 255.0f; + result.b = (b * 16 + b) / 255.0f; + result.a = (a * 16 + a) / 255.0f; + return result; + } + // #RRGGBB + if (length == 6) { + int r = (hex_char_to_int(hex_part[0]) << 4) + hex_char_to_int(hex_part[1]); + int g = (hex_char_to_int(hex_part[2]) << 4) + hex_char_to_int(hex_part[3]); + int b = (hex_char_to_int(hex_part[4]) << 4) + hex_char_to_int(hex_part[5]); + if (r < 0 || g < 0 || b < 0) + return std::nullopt; // Check hex_char_to_int results implicitly + result.r = r / 255.0f; + result.g = g / 255.0f; + result.b = b / 255.0f; + result.a = 1.0f; + return result; + } + // #RRGGBBAA + if (length == 8) { + int r = (hex_char_to_int(hex_part[0]) << 4) + hex_char_to_int(hex_part[1]); + int g = (hex_char_to_int(hex_part[2]) << 4) + hex_char_to_int(hex_part[3]); + int b = (hex_char_to_int(hex_part[4]) << 4) + hex_char_to_int(hex_part[5]); + int a = (hex_char_to_int(hex_part[6]) << 4) + hex_char_to_int(hex_part[7]); + if (r < 0 || g < 0 || b < 0 || a < 0) + return std::nullopt; // Check hex_char_to_int results implicitly + result.r = r / 255.0f; + result.g = g / 255.0f; + result.b = b / 255.0f; + result.a = a / 255.0f; + return result; + } + return std::nullopt; +} + +// --- RGB/RGBA 格式解析辅助函数 (重写为手动解析) --- +std::optional parse_rgb_rgba_color(const std::string& in_str) { + std::string lower_str = in_str; + // 转换为小写以便检查 "rgb(" 和 "rgba(" + std::ranges::transform(lower_str, lower_str.begin(), ::tolower); + + const size_t open_paren = lower_str.find('('); + const size_t close_paren = lower_str.find(')'); + + if (open_paren == std::string::npos || close_paren == std::string::npos || close_paren <= open_paren) { + return std::nullopt; // 括号不匹配或顺序错误 + } + + const auto& prefix = lower_str.substr(0, open_paren); + const bool is_rgba = prefix == "rgba"; + const bool is_rgb = prefix == "rgb"; + + if (!is_rgb && !is_rgba) { + return std::nullopt; // 前缀不是 rgb 或 rgba + } + + // **提取括号内的内容** + const auto& content = in_str.substr(open_paren + 1, close_paren - open_paren - 1); + + // **按逗号分割** + const auto& components_str = split_string(content, ','); + const size_t expected_components = is_rgba ? 4 : 3; + + if (components_str.size() != expected_components) { + return std::nullopt; // 组件数量不正确 + } + + std::array components; + int32_t index = 0; + bool uses_float = false; + bool uses_int = false; + + for (const std::string& comp_str_raw : components_str) { + // **去除每个组件的首尾空格** + const auto& comp_str = trim_whitespace(comp_str_raw); + if (comp_str.empty()) { + return std::nullopt; // 空组件 + } + + try { + // **检查是否包含小数点,以此判断是浮点数还是整数** + if (comp_str.find('.') != std::string::npos || comp_str.find('e') != std::string::npos || comp_str.find('E') != std::string::npos) { + // **尝试解析为浮点数** + const auto val_f = std::stof(comp_str); + components[index] = val_f; + uses_float = true; + } else { + // **尝试解析为整数** + const auto val_i = std::stoi(comp_str); + components[index] = val_i; + uses_int = true; + } + index++; + } catch (const std::invalid_argument&) { + return std::nullopt; // 无法解析为数字 + } catch (const std::out_of_range&) { + return std::nullopt; // 数字超出范围 (stoi/stof) + } + } + + // **不允许混合整数和浮点数格式** + if (uses_float && uses_int) { + // 一个特例:允许整数 0 或 1 出现在浮点数格式中,视为 0.0f 或 1.0f + // 但这里为了简化,我们严格区分,要么全是类整数,要么全是类浮点数 + // 如果需要支持混合,需要更复杂的逻辑判断每个分量 + return std::nullopt; + } + + linear_color result{}; + + if (uses_float) { + if (index != expected_components) + return std::nullopt; // 应该不会发生,但作为保险 + result.r = components[0]; + result.g = components[1]; + result.b = components[2]; + result.a = is_rgba ? components[3] : 1.0f; + return result; + } + + if (uses_int) { + if (index != expected_components) + return std::nullopt; // 应该不会发生 + result.r = components[0] / 255.0f; + result.g = components[1] / 255.0f; + result.b = components[2] / 255.0f; + result.a = is_rgba ? components[3] / 255.0f : 1.0f; + return result; + } + + // **如果既没有解析出浮点数也没有解析出整数 (例如空字符串),则失败** + return std::nullopt; +} + + +// --- linear_color 静态成员函数实现 --- +std::optional linear_color::from_string(const std::string& in_str) { + if (in_str.empty()) { return std::nullopt; } + + // **去除首尾空格** + std::string trimmed_str = trim_whitespace(in_str); + if (trimmed_str.empty()) { return std::nullopt; } + + // **委托给十六进制解析器** + if (trimmed_str[0] == '#') { + // **支持的十六进制格式:** #RGB, #RGBA, #RRGGBB, #RRGGBBAA + return parse_hex_color(trimmed_str); + } + + std::string lower_trimmed_str = trimmed_str; + std::ranges::transform(lower_trimmed_str, lower_trimmed_str.begin(), ::tolower); + + // **委托给 RGB/RGBA 解析器** + if (lower_trimmed_str.rfind("rgb", 0) == 0) { + // 检查是否以 "rgb" 或 "rgba" 开头 + // **支持的 RGB/RGBA 格式 (包括整数和浮点数,以及内部空格):** + // - rgb(r,g,b) + // - rgba(r,g,b,a) + return parse_rgb_rgba_color(trimmed_str); // 传递原始带大小写的字符串给解析器 + } + + // **未知格式** return std::nullopt; }