2009-10-17 2 views
5

Я должен преобразовать DWORD (без знака в длину) RGBA до четырех междунар вары (R, G, B и A) До сих пор у меня есть эта функция для преобразования 4 Интс в DWORD:Как я могу конвертировать из DWORD RGBA в ints?

unsigned long RGBA2DWORD(int iR, int iG, int iB, int iA) 
{ 
    return ((iA << 24) | (iR << 16) | (iG << 8) | iB); 
} 

Как я могу преобразовать его обратно?

Что-то вроде

struct RGBA 
{ 
    int R, G, B, A; 
}; 

RGBA DWORD2RGBA(unsigned long dwColor) 
{ 
    static RGBA tmp; 
    //.......conversion process 
    return tmp; 
} 

Любой вид помощи будет оценен по достоинству! :)

Благодаря

+1

Возможно, это просто опечатка, но вы должны использовать '' 'оператор в функции упаковки, а не' || '. – AnT

+5

Почему ваш «tmp» объявлен «статическим»? Вы намеревались вернуть указатель? – AnT

+0

Иногда я получаю предупреждение о компиляторе, когда возвращаю переменную, объявленную в функции. Поэтому я объявил это статическим, чтобы предотвратить предупреждение.? Нет? –

ответ

9

Если бы я тебя, я бы придерживаться мультипликативный аддитивных операций в упаковке/распаковке функции. Что-то вроде этого

unsigned long RGBA2DWORD(int iR, int iG, int iB, int iA) 
{   
    return ((iA * 256 + iR) * 256 + iG) * 256 + iB; 
} 

с симметричной распаковке функции

RGBA DWORD2RGBA(unsigned long dwColor) 
{   
    RGBA tmp; /* why did you declare it static??? */ 

    tmp.B = dwColor % 256; dwColor /= 256; 
    tmp.G = dwColor % 256; dwColor /= 256; 
    tmp.R = dwColor % 256; dwColor /= 256; 
    tmp.A = dwColor % 256; /* dwColor /= 256; */ 

    return tmp; 
} 

Заметим, что есть только одна «магическая константа» во всем коде.

Конечно, если у вас есть внешняя спецификация, написанная с точки зрения битовых шаблонов в упакованных данных, предпочтительной может быть версия, основанная на битовых и сдвиговых операциях. Тем не менее

unsigned long RGBA2DWORD(int iR, int iG, int iB, int iA) 
{   
    return (((((iA << 8) + iR) << 8) + iG) << 8) + iB; 
} 

RGBA DWORD2RGBA(unsigned long dwColor) 
{   
    RGBA tmp; /* why did you declare it static??? */ 

    tmp.B = dwColor & 0xFF; dwColor >>= 8; 
    tmp.G = dwColor & 0xFF; dwColor >>= 8; 
    tmp.R = dwColor & 0xFF; dwColor >>= 8; 
    tmp.A = dwColor & 0xFF; /* dwColor >>= 8; */ 

    return tmp; 
} 

имеет гораздо меньше «магических констант».

Теперь вы можете обертывать действия/подвыражения повторения в макросах или, лучше, встроенные функции и получать очень компактный и читаемый пакер/распаковщик.

+1

@Alex: А? Нет. Нет абсолютно никакой разницы с точки зрения производительности между этим и любым другим арифметическим решением, предлагаемым до сих пор. Где вы обнаружили проблемы с производительностью, заботитесь о разработке? – AnT

+0

Напротив, это, пожалуй, самое эффективное решение, поскольку компилятор сможет хранить только одну (или две) «магическую константу» в регистре. Решения с несколькими «магическими константами», скорее всего, заставят компилятор генерировать машинные инструкции со встроенными операндами, что заметно хуже по производительности. – AnT

+0

Я имею в виду это "((iA * 256) + iR) * 256 + iG) * 256 + iB" по сравнению с некоторыми простыми "сдвигами". Найти это очень запутанно. Однако я хотел бы принять этот комментарий. Вполне возможно, что я разговаривал из своей задницы ;-) – Alex

2

Вы можете пойти в другую сторону вокруг нравится:

мкА = >> 24 RGB; iR = (0x00FF0000 & rgb) >> 16; iG = (0x0000FF00 & rgb) >> 8; iB = (0x000000FF & rgb);

+2

Обратите внимание, что RGBA2DWORD неверен - он использует логические, а не побитовые операторы ИЛИ. См. Мой ответ ниже для правильной реализации. –

+0

Оооопс, да, просто скопируйте их с оригинального сообщения. – Alex

+0

@ Если вы обнаружите, что ваш ответ ошибочен, исправьте его. В противном случае мне придется сверлить его. –

3

Если вы не возражаете использовать целые числа байтов для RGBA, вы можете использовать объединение. [Редактировать Это общепринятый подход, и вы вряд ли найдете компилятор, который его не поддерживает, но, строго говоря, (так мне говорят) это незаконный хак. Лучший подход в большинстве случаев - сделать математическое или двоичное преобразование, но я оставлю половину своего ответа на месте, потому что он может помочь читателю понять, что делают люди, когда видят этот тип кода в реальном мир]

 
union RGBA 
{ 
    DWORD dword; 
    unsigned char RGBA[4]; 
    struct RGBAstruct 
    { 
     unsigned char b; 
     unsigned char g; 
     unsigned char r; 
     unsigned char a; 
    } 
}; 

Затем вы можете получить доступ к зеленым компонентам, как:

 
RGBA colour; 
int green = (int) colour.RGBA[2]; 

или

 
int green = (int) colour.RGBAstruct.g; 

и получить доступ к значению типа DWORD в

 
DWORD value = colour.dword; 

Если вам нужны значения RGBA для значений int или хотите использовать подход преобразования, вам необходимо использовать побитовые операторы.

Вы кодируете их почти правильно, но вам нужно использовать побитовый оператор OR, а не логический ИЛИ || Оператор:

 
DWORD value = (iA << 24) | (iR << 16) | (iG << 8) | iB; 

Для перехода в обратном направлении:

 
int iA = (value >> 24) & 0xff; 
int iR = (value >> 16) & 0xff; 
int iG = (value >> 8) & 0xff; 
int iB = (value) & 0xff; 
+0

P.S. Мой пример union/struct немного перепутан. Порядок значений RGBA будет зависеть от того, работаете ли вы на процессоре большого или маленького конца, поэтому вам может понадобиться RGBA или ABGR-порядок в вашей структуре для размещения значений в правильных местах. Немного экспериментирования (кодируйте значение 255,0,0,0 и узнайте, что вы получите) скажут вам, какой путь вам нужно сделать на вашей целевой платформе. –

+4

Ваш пример объединения путается более чем одним способом. Популярный «профсоюзный взлом» явно запрещен в C. За некоторыми исключениями, написание одного члена союза, а затем чтение другого приводит к неопределенному поведению. Это может не сработать над агрессивным компилятором. GCC, с его агрессивной оптимизацией «пишущих по типу», на данный момент избавился от «взлома профсоюза» (т. Е. Будет работать с GCC), но я не могу ручаться за всех компиляторов там. – AnT

+0

В вопросе говорится «C++» и не упоминается о компиляторе или платформе, поэтому я дал обобщенный ответ. Цель профсоюзов - позволить вам интерпретировать единую ячейку памяти как разные типы данных. Как вы говорите, будет сложно найти компилятор, который не поддерживает это. –

0

В действительности RGBA часть без знака длиной должно быть:

INT = Ir (значение) & 0xff;
int iG = (значение >> 8) & 0xff;
int iB = (значение >> 16) & 0xff;
int iA = (значение >> 24) & 0xff;

и весь вопрос о BGRA (согласно примеру вопроса), а не RGBA.

Смежные вопросы