Как однозначно упаковать ARGB в одно целое число? - PullRequest
11 голосов
/ 09 сентября 2011

У меня есть четыре целочисленных значения (0 - 255) для цветовой карты ARGB.

Теперь я хочу сделать уникальное число с плавающей точкой или целое число из этих четырех целых чисел. Можно ли сделать это следующим образом?

sum  = 4 * 255 + A;
sum += 3 * 255 + R;
sum += 2 * 255 + G;
sum += 1 * 255 + B;

Является ли значение действительно уникальным?

Ответы [ 4 ]

26 голосов
/ 09 сентября 2011

Вы пытаетесь сделать базовое преобразование или что-то в этом роде. В любом случае логика похожа на конвертацию базы. 4 байта = 32 бита. Так что 32-разрядное целое число без знака будет хорошо.

В этом случае у вас есть:

ARGB = A<<24 + R<<16 + G<<8 + B

это так:
у вас есть 4 байта данных, что означает

xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx

, где X это 1 или 0 значащий бит. Вы отображаете их так:

AAAAAAAA RRRRRRRR GGGGGGGG BBBBBBBB

и тогда все, что вам нужно сделать, это добавить их, но перед этим вы сдвинете биты. Вы сдвигаете A бит влево на 8 * 3 (чтобы выйти за пределы R, G и B бит), затем сдвигаете R бит на 8 * 2, и так на.

В итоге вы добавите эти 32-битные целые числа:

AAAAAAAA 00000000 00000000 00000000
00000000 RRRRRRRR 00000000 00000000
00000000 00000000 GGGGGGGG 00000000
00000000 00000000 00000000 BBBBBBBB

Где A, R, G, B могут быть либо 0, либо 1 и представлять в целом 8-битное значение канала. Затем вы просто добавляете их и получаете результат. Или, как писал DarkDust , используйте не оператор +, а оператор | (поразрядный или), поскольку в данном конкретном случае он должен быть быстрее.

9 голосов
/ 09 сентября 2011

Вы можете сделать это:

Предполагая, что a, r, g и b будут иметь тип unsigned char / uint8_t:

uint32_t color = 0;
color |= a << 24;
color |= r << 16;
color |= g << 8;
color |= b;

Или более общий (a, r, g и b любого целого типа):

uint32_t color = 0;
color |= (a & 255) << 24;
color |= (r & 255) << 16;
color |= (g & 255) << 8;
color |= (b & 255);

Это даст вам уникальное целое число для каждой комбинации ARGB.Вы можете получить значения обратно так:

a = (color >> 24) & 255;
r = (color >> 16) & 255;
g = (color >> 8) & 255;
b = color & 255;
5 голосов
/ 09 сентября 2011

Не совсем. Вам нужно использовать битовое смещение, а не простое умножение.

Каждое значение в вашей цветовой карте имеет длину 8 байт, верно? Таким образом, чтобы результирующее число было уникальным, оно должно связать их все вместе, в общей сложности 8 * 4 = 32 бита. Посмотрите на следующее:

Вы хотите взять:

AAAAAAAA
RRRRRRRR
GGGGGGGG
BBBBBBBB

и сделайте так:

AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB

Это означает, что вы должны добавить следующее:

AAAAAAAA000000000000000000000000
        RRRRRRRR0000000000000000
                GGGGGGGG00000000
                        BBBBBBBB
--------------------------------
AAAAAAAARRRRRRRRGGGGGGGGBBBBBBBB

Мы выполняем это, сдвигая бит влево. Взяв A и сдвинув 24 бита влево, вы получите AAAAAAAA, а затем 24 0 бит, как мы и хотим. Следуя этой логике, вы захотите сделать:

sum = A << 24 + R << 16 + G << 8 + B;

Чтобы проиллюстрировать, почему то, что вы предлагаете (с использованием умножения), не работает, то, что вы предлагаете, приводит к следующим двоичным числам, которые вы можете увидеть как перекрывающиеся:

255 * 1 = 0011111111
255 * 2 = 0111111110
255 * 3 = 1011111101
255 * 4 = 1111111100

Кроме того, простое добавление значений A, R, G, B к полученному числу всегда будет постоянным. Упрощая вашу математику выше, мы получаем:

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

К сожалению.

0 голосов
/ 03 декабря 2018
#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;
}
...