How to pack ARGB to one integer uniquely?
I have four integer values (0 - 255) for an ARGB color map.
Now I want to make a unique float or integer of these four integers. Is it possible to do it l开发者_如何学运维ike the following?
sum = 4 * 255 + A;
sum += 3 * 255 + R;
sum += 2 * 255 + G;
sum += 1 * 255 + B;
Is the value really unique?
You are trying to do a base convert or something of that sort. Anyway the logic is like in base converting. 4 bytes = 32 bit. So 32 bit unsigned integer would do well.
In this case, you have:
ARGB = A<<24 + R<<16 + G<<8 + B
it's like this:
you have 4 bytes of data, meaning
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
where X is either 1 or 0 valued bit. You map them like this:
AAAAAAAA RRRRRRRR GGGGGGGG BBBBBBBB
and then all you have to do is to add them, but before that you shift the bits. You shift the A
bits to the left, by 8*3 (to be beyond the limits of R
, G
and B
bits), then shift the R
bits by 8*2, and so on.
You end up adding these 32 bit integers:
AAAAAAAA 00000000 00000000 00000000
00000000 RRRRRRRR 00000000 00000000
00000000 00000000 GGGGGGGG 00000000
00000000 00000000 00000000 BBBBBBBB
Where A
, R
, G
, B
can be either 0
or 1
, and represent as a whole, the 8 bit value of the channel. Then you simply add them, and obtain the result. Or as DarkDust wrote, use not the +
operator, but instead the |
(bitwise or) operator, since it should be faster in this particular case.
You could do this:
Assuming a
, r
, g
and b
to be of type unsigned char
/uint8_t
:
uint32_t color = 0;
color |= a << 24;
color |= r << 16;
color |= g << 8;
color |= b;
Or more general (a
, r
, g
and b
being of any integer type):
uint32_t color = 0;
color |= (a & 255) << 24;
color |= (r & 255) << 16;
color |= (g & 255) << 8;
color |= (b & 255);
This will give you a unique integer for every ARGB combination. You can get the values back like this:
a = (color >> 24) & 255;
r = (color >> 16) & 255;
g = (color >> 8) & 255;
b = color & 255;
Not quite. You need to use bit-shifting and not simple multiplication.
Each value in your color map is 8 bytes long, correct? So in order for the resulting number to be unique, it must string them all together, for a total of 8*4=32 bits. Look at the following:
You want to take:
AAAAAAAA RRRRRRRR GGGGGGGG BBBBBBBB
and make it look like:
AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB
This means you have to add the following together:
AAAAAAAA000000000000000000000000 RRRRRRRR0000000000000000 GGGGGGGG00000000 BBBBBBBB -------------------------------- AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB
We accomplish this by bit-shifting to the left. Taking A
and shifting 24 bits to the left will produce AAAAAAAA
followed by 24 0
bits, just like we want. Following that logic, you will want to do:
sum = A << 24 + R << 16 + G << 8 + B;
To illustrate why what you suggest (using multiplication) does not work, what you suggest results in the following binary numbers, which you can see overlap:
255 * 1 = 0011111111 255 * 2 = 0111111110 255 * 3 = 1011111101 255 * 4 = 1111111100
Furthermore, simply adding your A, R, G, B values to the resulting number will always be constant. Simplifying your math above we get:
4 * 255 + A + 3 * 255 + R + 2 * 255 + G + 1 * 255 + B 255 * (4 + 3 + 2 + 1) + A + R + G + B 255 * (10) + A + R + G + B 2550 + A + R + G + B
Oops.
#include<bitset>
void printBits(string s, int x)
{
bitset <64> b(x);
cout<<"\n"<<s<< " " << b;
}
long RGB(int a, int r, int g, int b)
{
printBits("alpha ", a);
printBits("red ", r);
printBits("green ", g);
printBits("blue ", b);
long l = 0;
l |= a << 24;
l |= r << 16;
l |= g << 8;
l |= b;
printBits("packed ARGB", l);
return l;
}
精彩评论