You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何`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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.02 15:03:14