我通常使用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';
这是一个现场演示。