颜色解析
This commit is contained in:
parent
d596ae4c09
commit
84330d5069
@ -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<linear_color> 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<mtext_block>();
|
||||
text_block2->set_text(U"Hello, World!");
|
||||
|
@ -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 <algorithm>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
// --- 辅助函数 ---
|
||||
|
||||
// 将单个十六进制字符转换为整数 (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> 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<std::string> split_string(const std::string& str, char delimiter) {
|
||||
std::vector<std::string> tokens;
|
||||
std::string token;
|
||||
std::istringstream tokenStream(str);
|
||||
while (std::getline(tokenStream, token, delimiter)) {
|
||||
tokens.push_back(token);
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
|
||||
// --- 十六进制格式解析辅助函数 (保持不变) ---
|
||||
std::optional<linear_color> 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<unsigned char>(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<float>(r_int) / 255.0f;
|
||||
result.g = static_cast<float>(g_int) / 255.0f;
|
||||
result.b = static_cast<float>(b_int) / 255.0f;
|
||||
result.a = static_cast<float>(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<float>(r_int) / 255.0f;
|
||||
result.g = static_cast<float>(g_int) / 255.0f;
|
||||
result.b = static_cast<float>(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<linear_color> 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<float, 4> 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> 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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user