GIF-анимация на Ассемблере
GIF-анимация на Ассемблере
Выводить статическое изображение на форму мы уже научились, причем разными способами, теперь давайте попробуем вывести анимированный GIF-файл. Для этого даже не понадобится углубляться в дебри формата, будем работать с высокоуровневыми функциями GDI+.
Сперва надо инициализировать систему GDI+ и загрузить изображение. Это мы все уже делали не один раз, тут ничего сложного. Напомню только, что имя файла изображения должно быть в юникоде.
Code (Assembler) : Убрать нумерацию
- ; Структура для работы с GDI+
- struct GdiplusStartupInput
- GdiplusVersion dd ?
- DebugEventCallback dd ?
- SuppressBackgroundThread dd ?
- SuppressExternalCodecs dd ?
- ends
Code (Assembler) : Убрать нумерацию
- ; Инициализация GDI+
- mov [gdiplusSInput.GdiplusVersion],1
- mov [gdiplusSInput.DebugEventCallback],0
- mov [gdiplusSInput.SuppressBackgroundThread],0
- mov [gdiplusSInput.SuppressExternalCodecs],0
- invoke GdiplusStartup,gdiplusToken,gdiplusSInput,0
- ; Загрузить картинку из файла
- invoke GdipLoadImageFromFile,fname,hImage
Code (Assembler) : Убрать нумерацию
- PropertyTagFrameDelay = 0x5100
- ...
- ; Проверить количество пространств
- invoke GdipImageGetFrameDimensionsCount,[hImage],tmp
- cmp [tmp],0
- je loc_error
- ; Получить идентификатор первого пространства
- invoke GdipImageGetFrameDimensionsList,[hImage],dimID,1
- ; Получить количество кадров в первом пространстве
- invoke GdipImageGetFrameCount,[hImage],dimID,frameCount
- ; Получить значение задержек между кадрами
- invoke GdipGetPropertyItemSize,[hImage],PropertyTagFrameDelay,tmp
- mov eax,[tmp]
- shl eax,2
- invoke GdipAlloc,eax
- mov [delayData],eax
- invoke GdipGetPropertyItem,[hImage],PropertyTagFrameDelay,\
- [tmp],[delayData]
Дальше дело техники. Надо вывести поочередно все кадры, учитывая время задержки между ними. Для этого взводится таймер, на каждый тик которого уменьшается интервал текущей задержки.
Code (Assembler) : Убрать нумерацию
- ; Данные для самого первого кадра и нулевая задержка для запуска
- mov [dDelay],0
- mov [dFrame],0
- invoke SetTimer,[hwnddlg],1,100,0
Code (Assembler) : Убрать нумерацию
- ; Интервал между кадрами уже прошел?
- cmp [dDelay],0
- je @f
- dec [dDelay]
- jmp processed
- @@:
- ; Установить следующий кадр
- invoke GdipImageSelectActiveFrame,[hImage],dimID,[dFrame]
- mov [hBitmap],0
- ; Создать HBITMAP для установки на static
- invoke GdipCreateHBITMAPFromBitmap,[hImage],\
- hBitmap,0x00FFFFFF
- ; Получить размеры изображения
- invoke GetObject,[hBitmap],sizeof.BITMAP,bm
- ; Создать виртуальный битмап для превьюшки
- invoke GetDC,NULL
- invoke CreateCompatibleBitmap,eax,IMG_X,IMG_Y
- mov [imgBitmap],eax
- invoke CreateCompatibleDC,NULL
- mov [hDC1],eax
- invoke CreateCompatibleDC,NULL
- mov [hDC2],eax
- invoke SelectObject,[hDC1],[imgBitmap]
- mov [hOld1],eax
- invoke SelectObject,[hDC2],[hBitmap]
- mov [hOld2],eax
- ; Размеры области заливки
- mov [rct.top],0
- mov [rct.left],0
- mov [rct.bottom],IMG_Y
- mov [rct.right],IMG_X
- ; Заливка фона виртуального битмапа
- invoke GetSysColorBrush,COLOR_BTNFACE
- invoke FillRect,[hDC1],rct,eax
- ; При необходимости подогнать большое изображение
- ; под размер области превьюшки
- mov eax,[bm.bmWidth]
- mov [dImageWidth],eax
- mov eax,[bm.bmHeight]
- mov [dImageHeight],eax
- ; Размеры больше окна превьюшки?
- cmp [dImageWidth],IMG_X
- ja thumb_fix_size
- cmp [dImageHeight],IMG_Y
- ja thumb_fix_size
- ; Нарисовать как есть
- jmp thumb_draw
- thumb_fix_size:
- ; Пресчет размеров по горизонтали
- mov eax,[dImageWidth]
- cmp eax,[dImageHeight]
- jb @f
- mov eax,[dImageHeight]
- xor edx,edx
- mov ecx,IMG_X
- imul ecx
- xor edx,edx
- mov ecx,[dImageWidth]
- idiv ecx
- mov [dImageHeight],eax
- mov [dImageWidth],IMG_X
- ; Пресчет размеров по вертикали
- cmp [dImageHeight],IMG_Y
- jbe thumb_draw
- @@:
- mov eax,[dImageWidth]
- xor edx,edx
- mov ecx,IMG_Y
- imul ecx
- xor edx,edx
- mov ecx,[dImageHeight]
- idiv ecx
- mov [dImageWidth],eax
- mov [dImageHeight],IMG_Y
- thumb_draw:
- ; Смещение по X
- mov eax,IMG_X
- sub eax,[dImageWidth]
- shr eax,1
- mov [ImageX],eax
- ; Смещение по Y
- mov eax,IMG_Y
- sub eax,[dImageHeight]
- shr eax,1
- mov [ImageY],eax
- ; Наложить изображение в центр виртуального битмапа
- invoke SetStretchBltMode,[hDC1],HALFTONE
- invoke StretchBlt,[hDC1],[ImageX],[ImageY],\
- [dImageWidth],[dImageHeight],[hDC2],0,0,\
- [bm.bmWidth],[bm.bmHeight],SRCAND
- invoke SelectObject,[hDC1],[hOld1]
- invoke DeleteDC,[hDC1]
- invoke SelectObject,[hDC2],[hOld2]
- invoke DeleteDC,[hDC2]
- ; Установить виртуальный битмап на static
- invoke SendDlgItemMessage,[hwnddlg],ID_IMG,\
- STM_SETIMAGE,IMAGE_BITMAP,[imgBitmap]
- invoke DeleteObject,[hBitmap]
Code (Assembler) : Убрать нумерацию
- ; Высчитать интервал между следующим кадром
- mov eax,[dFrame]
- shl eax,2
- add eax,[delayData]
- add eax,16
- mov eax,[eax]
- xor edx,edx
- mov ecx,60
- imul ecx
- mov ecx,1000
- idiv ecx
- mov [dDelay],eax
- ; Следующий кадр
- mov eax,[dFrame]
- inc eax
- cmp eax,[frameCount]
- jb @f
- xor eax,eax
- @@:
- mov [dFrame],eax
В приложении пример программы с исходным текстом, которая загружает с диска анимированный GIF-файл и выводит его на форму.
Просмотров: 1269 | Комментариев: 7
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(26.05.2024 в 14:40):
Нет
gob
(26.05.2024 в 14:35):
Кстати, не пробовали создать гифку на ассемблере? Выходит шляпа с задержками между кадрами.
ASMiral
(25.02.2022 в 18:21):
Да я примерно-то в курсе, что у вас везде аттачи с готовыми бинарниками. Уж не первый год ваш сайт читаю. Но мне всегда интересно самому и код глянуть и скомпилировать.
А за отзывчивость - спасибо, а то не все же бывают в курсе где и что лежит. Я вон как-то, помню, не мог догадаться как цитаты у вас в блоге вставляются. Но слава богу Манхантер, добрая душа пояснил, для особо одаренных. ))
ManHunter
(25.02.2022 в 18:10):
Он же в аттаче есть в готовом скомпилированном виде.
ASMiral
(25.02.2022 в 18:09):
А мне иногда даже паяльника бывает мало. В таких случаях применяю еще и напиильНЕГ, молоток и зубило. ))
P.S. А, вообще, тема интересная. Нужно будет вникнуть, когда будет свободное время. Примерчик скомпилировать.
Спасибо.
ManHunter
(25.02.2022 в 17:39):
"То, что не удается запрограммировать на Ассемблере, приходится паять"
NobootRecord
(23.02.2022 в 18:06):
Очень интересная штука - не знал, что на Ассемблере можно такое вытворять.
Самое прикольное - эта статья написана в мой день рождения :)
Самое прикольное - эта статья написана в мой день рождения :)
Добавить комментарий
Заполните форму для добавления комментария