C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Сдвиговые операции, char, 3 байта в 2.
cobol
Отправлено: 27.11.2005, 20:22


Не зарегистрирован







Есть буффер с тремя байтами (r,g,cool.gif 24 бита. Нужно после дизеренга получить 15 байт, и уместить их в 2 байта. Т.е. было по 8 бит на цвет, результат должен быть 5 бит на цвет (+1 бит пустой, роли особой не играет сейчас).

Итак, буфер есть, функция дизеренга есть (которая преобразует эти 3 байта в 5 битные значения. И выдает как результат обновленные (но все еще 3) байта.

Нужно получить 2 байта.

Т.е. было:

char *buf[2];

char buf[0]=255;
char buf[1]=255;
char buf[2]=255;

далее dither(buf);

и имеем:

char buf[0]=248;
char buf[1]=248;
char buf[2]=248;

Теперь из результата нужно сделать 2 байта. Т.е. сдвинуть их в кучу. Как это релизовать и как быть с char ? сначала в int ковертить, потом чтото творить со сдвигами, или как ?
Grigoriy
Отправлено: 28.11.2005, 05:27


Мастер участка

Группа: Участник
Сообщений: 381



Это интересный вопрос из интересующих меня задач.
Вы хотите получить 16-битное значение цвета пиксела исходя из 24-битного значения цвета пиксела.

Это правильнее всего сделать на встроенном ассемблере.
Привожу код с комментариями.
Вот что у меня получилось

[CODE]
typedef unsigned char byte; //тип однобайтной ячейки памяти
short int pixelcolor16; //переменная результатирующим значением цвета
byte* addrpixelcolor24;//адрес переменной с исходным значением цвета
addrpixelcolor24=(byte*)malloc(3);//выделим память под три байта для 24-го значения цвета
........
//Здесь идут инструкции для приема 24-битного значения цвета пиксела
........
dither(addrpixelcolor24);/*функция выполняет манипуляцию битами 24-битного значения цвета пиксела*/
........
//Начало инструкций упаковки битов
asm
{
/*eax, ebx, ecx, edx, edi, esi, esp, ebp — 32-битные регистры общего назначения микропроцессора;
ax, bx, cx, dx, di, si, sp, bp — 16-ти битные регистры общего назначения процессора, каждый из которых является младшей частью соответственного 32-битного регистра;
al, bl, cl, dl — 8-ми битные регистры общего назначения процессора, каждый из которых является младшей частью соответственного 32-битного регистра
*/
push eax;//все используемые регистры в сегмент стека программы
push ebx;
push ecx;
push edx;
push edi;
mov edi,addrpixelcolor24;/*адрес 24-битного значения, полученного dither в edi*/
mov bl,[edi];//младший байт 24-битного значения из памяти в bl
mov cl,[edi+1];//следующий байт из памяти в cl
mov dl,[edi+2];//старший байт из памяти в dl
shr bl,3;//сдвигаем биты регистров вправо на 3 разряда
shr cl,3;
shr dl,3;
shrd eax,ebx,5;/*эта инструкция заставляет процессор сдвинуть содержимое eax на 5 разрядов вправо, после чего все биты eax окажутся сдвинутыми на 5 разрядов вправо, 5 младших битов ebx копируется на место старших 5 битов eax*/
shrd eax,ecx,5;//то же с другими источниками
shrd eax,edx,5;
//и так — мы упаковали биты, но они находятся слева, а не справа
shr eax,17;//сместим все биты eax на 17 разрядов вправо
/*после этого все 15 битов, которые сдвинул процессор окажутся полностью в младшей 16-ти битной части(регистре ax) 32-битного eax*/
mov pixelcolor16,ax;//запишем получившееся значение из eax в память
pop edi;/*не забываем извлекать сохраненные в сегменте стека программы регистры (в обратной последовательноти!)*/
pop edx;
pop ecx;
pop ebx;
pop eax;
};

Отредактировано Grigoriy — 28/11/2005, 05:34
Grigoriy
Отправлено: 28.11.2005, 05:48


Мастер участка

Группа: Участник
Сообщений: 381



Во втором сообщении я предупреждаю Вас, cobol, что три команды
по здвигу регистров bl, cl, dl на 3 разряда вправо нужны потому, что в данном вашем случае программа манипуляции битами просто обнуляет три младшие бита в 8-ми битном значении интенсивности цвета. Поэтому значащие 5 битов находятся слева.
Например, вы пишете, что исходное значение интенсивности цвета было 255, то есть в двоичном виде это восемь единиц — 11111111.
А получилось 248, то есть 11111000.
Важно.
Если бы 5 значащих битов были бы справа, то сдвигать вправо на 3 разряда не нужно было бы.

Отредактировано Grigoriy — 28/11/2005, 05:49
Георгий
Отправлено: 28.11.2005, 08:55


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



QUOTE (cobol @ 27/11/2005, 21:22)
Нужно получить 2 байта.

char buf[0]=248;
char buf[1]=248;
char buf[2]=248;

Теперь из результата нужно сделать 2 байта. Т.е. сдвинуть их в кучу. Как это релизовать и как быть с char ? сначала в int ковертить, потом чтото творить со сдвигами, или как ?

CODE
unsigned short result=0;
for(int i=0;i<3;++i)
     result|=(unsigned short)((((unsigned short)(buf[i]))>>3)<<(5*i))
Grigoriy
Отправлено: 28.11.2005, 10:51


Мастер участка

Группа: Участник
Сообщений: 381



QUOTE (Георгий @ 28/11/2005, 08:55)
CODE
unsigned short result=0;
for(int i=0;i<3;++i)
result|=(unsigned short)((((unsigned short)(buf[i]))>>3)<<(5*i))

Или так

CODE

unsigned short result;
result=(buf[0]>>3)+((buf[1]&248)<<2)+((buf[2]&248)<<7);

Хотя краткость программы на C++ вовсе не означает эффективность машинного кода. wink.gif

Отредактировано Grigoriy — 28/11/2005, 10:59

Вернуться в Вопросы программирования в C++Builder