У меня есть пример:
unsigned int dwColor = 0xAABBCCFF; //Light blue color
И его параметры слева направо: «альфа, красный, зеленый, синий»; каждый параметр требует двух шестнадцатеричных значений.
Максимальное значение каждого параметра 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
РЕДАКТИРОВАТЬ: я только что видел союз, но отвечающий говорит, что это UB (неопределенное поведение). Кто-нибудь знает лучшее решение? 🙂
Я обычно использую 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), см. этот вопрос от Лучиан Григоре.
РЕДАКТИРОВАТЬ 2:
Итак, еще один способ сломать DWORD
на компоненты, избегая 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
Предупреждение! не все цветовые форматы будут соответствовать этому шаблону!
Но, IMHO, более подходящее решение — объединить функцию с перечислением, поскольку мы работаем с ограниченным пакетом значений для индекса:
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';
И вот живое демо.
Других решений пока нет …