为何`XLookupColor()`成功而`xcb_lookup_color()`调用失败?
XLookupColor与xcb_lookup_color的颜色解析差异及处理方案
测试代码
#include <X11/Xlib.h> #include <string.h> #include <xcb/xcb.h> #include <stdio.h> int main(void) { const char *s = "#ff0000"; Display *display = XOpenDisplay(NULL); XColor exact, screen_c; printf("%d\n", XLookupColor(display, XDefaultColormap(display, XDefaultScreen(display)), s, &exact, &screen_c)); printf("rgb = %ld %ld %ld\n", exact.red, exact.green, exact.blue); int screen_index; xcb_connection_t *c = xcb_connect(NULL, &screen_index); const xcb_setup_t *setup = xcb_get_setup(c);; xcb_screen_t *screen; xcb_screen_iterator_t iterator; int i = screen_index; for (iterator = xcb_setup_roots_iterator(setup); iterator.rem > 0; i--, xcb_screen_next(&iterator)) { if (i == 0) { screen = iterator.data; break; } } xcb_lookup_color_cookie_t cookie = xcb_lookup_color(c, screen->default_colormap, strlen(s), s); xcb_generic_error_t *error; xcb_lookup_color_reply_t *reply = xcb_lookup_color_reply(c, cookie, &error); if (reply == NULL) { printf("error: %u\n", error->error_code); } return 0; }
执行结果
执行命令:
cc a.c -lX11 -lxcb -o a.out ; ./a.out
得到以下结果:
XLookupColor()成功解析#ff0000,返回正确的RGB分量值xcb_lookup_color()调用失败,返回NULL,错误码15(名称错误)- 当将颜色字符串改为
"red"时,xcb_lookup_color()可正常工作
原因
Xlib的XLookupColor()在客户端本地做了额外处理:先检测到#开头的十六进制颜色格式,直接在本地解析为RGB值,再与X服务器交互;而XCB的xcb_lookup_color()是直接转发X服务器的LookupColor请求,而X服务器本身并不支持解析#格式的颜色字符串——XLookupColor手册中提到#...格式不再推荐,XCB作为更底层的库,没有封装这个客户端侧的解析逻辑。
解决方案:手动解析#格式颜色值
由于XCB不提供#格式的颜色解析,需要自行实现客户端侧的解析逻辑。以下是一个解析#rgb或#rrggbb格式的示例函数:
#include <stdint.h> #include <stdlib.h> #include <string.h> // 解析#rrggbb或#rgb格式的颜色字符串,返回XCB使用的16位RGB分量(范围0-65535) int parse_hex_color(const char *s, uint16_t *r, uint16_t *g, uint16_t *b) { if (!s || *s != '#') return 0; s++; size_t len = strlen(s); if (len != 3 && len != 6) return 0; uint8_t rr, gg, bb; if (len == 3) { // 扩展三位格式为六位:#rgb → #rrggbb rr = (strtol(s, NULL, 16) & 0x0F) * 0x11; gg = (strtol(s+1, NULL, 16) & 0x0F) * 0x11; bb = (strtol(s+2, NULL, 16) & 0x0F) * 0x11; } else { rr = strtol(s, NULL, 16); gg = strtol(s+2, NULL, 16); bb = strtol(s+4, NULL, 16); } // 转换为XCB使用的16位分量(0-65535) *r = (uint16_t)(rr * 257); *g = (uint16_t)(gg * 257); *b = (uint16_t)(bb * 257); return 1; }
使用时可以先判断颜色字符串是否以#开头:如果是,调用上述函数解析得到RGB值;否则再使用xcb_lookup_color()查询颜色名称。
内容的提问来源于stack exchange,提问作者cutecoder
相关产品推荐
相关产品推荐

