Как извлечь цветовую переменную DWORD в ее параметры? (десятичный тип)

У меня есть пример:

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 (неопределенное поведение). Кто-нибудь знает лучшее решение? 🙂

0

Решение

Я обычно использую 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';

И вот живое демо.

1

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector