Question

I have the example :

unsigned int dwColor = 0xAABBCCFF; //Light blue color
  • And its parameters from left to right are : "alpha, red, green, blue"; each parameter requires two hexadecimal values.

  • The maximum value of each parameter is 255; lowest : 0

And, how to extract then convert all parameters of a DWORD color to decimals?

I like the value range "0.00 -> 1.00". For example :

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

EDIT : I've just seen union, but the answerer says it's UB (Undefined Behaviour). Does anyone know the better solution? :)

Was it helpful?

Solution

I usually use an 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];

If you need to treat it as a float value:

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;

EDIT:

As mentioned in the comments below, this use of union is Undefined Behaviour (UB), see this question from Luchian Grigore.


EDIT 2:

So, another way to break a DWORD into components avoiding the union is using some bitwise magic:

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

But I do not advise the macro solution, I think is better to use a function:

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;
}

How it works? Lets supose we call get_component(0xAABBCCFF, 0):

shift = 0 * 8
shift = 0

mask = 0xFF << 0
mask = 0x000000FF

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

0x000000FF >> 0 = 0xFF

Lets supose we call get_component(0xAABBCCFF, 2):

shift = 2 * 8
shift = 16

mask = 0xFF << 16
mask = 0x00FF0000

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

0x00BB0000 >> 16 = 0xBB

Warning! not all color formats will match that pattern!

But IMHO, the neater solution is to combine the function with an enum, since we're working with a limited pack of values for the index:

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;
}

The last approach ensures that the bitwise operations will only be performed if the input parameters are valid, this would be an example of usage:

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';

And here is a live demo.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top