1

我有这个例子:

unsigned int dwColor = 0xAABBCCFF; //Light blue color
  • 其参数从左到右依次为:“alpha, red, green, blue”;每个参数需要两个十六进制值。

  • 每个参数的最大值为255;最低:0

而且,如何提取然后将 DWORD 颜色的所有参数转换为小数?

我喜欢值范围"0.00 -> 1.00"。例如 :

float alpha = convert_to_decimal(0xAA); //It gives 0.666f
float red = convert_to_decimal(0xBB); //It gives 0.733f
float green = convert_to_decimal(0xCC); //It gives 0.800f
float blue = convert_to_decimal(0xFF); //It gives 1.000f

编辑:我刚刚看到union,但回答者说它是 UB(未定义行为)。有谁知道更好的解决方案?:)

4

1 回答 1

1

我通常使用union

union color
{
    unsigned int value;
    unsigned char component[4];
};

color c;
c.value = 0xAABBCCFF;
unsigned char r = c.component[0];
unsigned char g = c.component[1];
unsigned char b = c.component[2];
unsigned char a = c.component[3];

如果您需要将其视为浮点值:

float fr = c.component[0] / 255.0f;
float fg = c.component[1] / 255.0f;
float fb = c.component[2] / 255.0f;
float fa = c.component[3] / 255.0f;

编辑:

正如下面的评论中提到的,这种使用union是未定义的行为(UB),请参阅Luchian Grigore这个问题


编辑2:

因此,另一种将 aDWORD 分解为组件避免的union方法是使用一些按位魔法:

#define GET_COMPONENT(color, index) (((0xFF << (index * 8)) & color) >> (index * 8))

但我不建议使用宏解决方案,我认为最好使用一个函数:

unsigned int get_component(unsigned int color, unsigned int index)
{
    const unsigned int shift = index * 8;
    const unsigned int mask = 0xFF << shift;
    return (color & mask) >> shift;
}

这个怎么运作?假设我们调用get_component(0xAABBCCFF, 0)

shift = 0 * 8
shift = 0

mask = 0xFF << 0
mask = 0x000000FF

0x000000FF &
0xAABBCCFF
----------
0x000000FF

0x000000FF >> 0 = 0xFF

假设我们调用get_component(0xAABBCCFF, 2)

shift = 2 * 8
shift = 16

mask = 0xFF << 16
mask = 0x00FF0000

0x00FF0000 &
0xAABBCCFF
----------
0x00BB0000

0x00BB0000 >> 16 = 0xBB

警告!并非所有颜色格式都与该模式匹配!

但是恕我直言,更简洁的解决方案是将函数与枚举结合起来,因为我们正在使用有限的索引值包:

enum color_component
{
    A,B,G,R
};

unsigned int get_component(unsigned int color, color_component component)
{
    switch (component)
    {
        case R:
        case G:
        case B:
        case A:
        {
            const unsigned int shift = component * 8;
            const unsigned int mask = 0xFF << shift;
            return (color & mask) >> shift;            
        }

        default:
            throw std::invalid_argument("invalid color component");
    }

    return 0;
}

最后一种方法确保仅在输入参数有效时才执行按位运算,这将是一个使用示例:

std::cout
    << "R: " << get_component(the_color, R) / 255.0f << '\n'
    << "G: " << get_component(the_color, G) / 255.0f << '\n'
    << "B: " << get_component(the_color, B) / 255.0f << '\n'
    << "A: " << get_component(the_color, A) / 255.0f << '\n';

这是一个现场演示

于 2013-01-28T07:12:28.800 回答