
Вывод изображения на Ассемблере с помощью GDI+
При разработке своих программ пришлось столкнуться с задачей загрузки произвольного изображения из файла или из памяти и последующего вывода его в диалоговое окно. Есть несколько вариантов, как это сделать, но, на мой взгляд, наиболее корректный путь - воспользоваться функциями стандартной библиотеки GDI+. Она поддерживается всеми современными системами Windows, начиная с Windows XP и обладает очень широкими возможностями по обработке изображений.Сперва в сегменте данных надо определить структуру GdiplusStartupInput, про которую FASM не знает. Да и в импорте тоже придется самостоятельно приписать несколько функций из библиотеки GDI+, так как в стандартных инклудах FASM их тоже нет. Описание остальных переменных, используемых в коде, вы можете посмотреть в прилагаемом к статье исходнике.
Code (Assembler) : Убрать нумерацию
- ; Структура для работы с GDI+
- struct GdiplusStartupInput
- GdiplusVersion dd ?
- DebugEventCallback dd ?
- SuppressBackgroundThread dd ?
- SuppressExternalCodecs dd ?
- ends
- ; Размеры превьюшки
- IMG_X = 332
- IMG_Y = 248
- ; ID статика для вывода изображения
- ID_IMG = 100
- ; Имя файла для вывода на форму
- fname db 'picture.jpg',0
Теперь несколько слов о самом коде. Я постарался сделать его максимально универсальным, он не только выводит изображение на STATIC, но при этом подгоняет ее под размер этого поля, а также размещает изображение в центре. Если в вашем проекте подобные навороты не нужны, то можно оставить только загрузку и вывод изображения.
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 MultiByteToWideChar,CP_ACP,0,fname,\
- MAX_PATH*2,buff,MAX_PATH*2
- ; Создать битмап из файла
- invoke GdipCreateBitmapFromFile,buff,xTmp
- or eax,eax
- jnz clear_gdi3
- ; Изображение корректное?
- invoke GdipGetImageWidth,[xTmp],tmp
- cmp [tmp],0
- je clear_gdi2
- invoke GdipGetImageHeight,[xTmp],tmp
- cmp [tmp],0
- je clear_gdi2
- mov [hBitmap],0
- ; Создать HBITMAP для установки на static
- invoke GdipCreateHBITMAPFromBitmap,[xTmp],\
- hBitmap,0x00FFFFFF
- cmp [hBitmap],0
- jz clear_gdi2
- ; Получить размеры изображения
- invoke GetObject,[hBitmap],sizeof.BITMAP,bm
- or eax,eax
- jnz @f
- invoke GdipGetImageWidth,[xTmp],bm.bmWidth
- invoke GdipGetImageHeight,[xTmp],bm.bmHeight
- ; Изображение корректное?
- cmp [bm.bmWidth],0
- jz clear_gdi1
- cmp [bm.bmHeight],0
- jz clear_gdi1
- @@:
- ; Создать виртуальный битмап для превьюшки
- 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],SRCCOPY
- 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 GdipDisposeImage,[xTmp]
- clear_gdi1:
- invoke DeleteObject,[hBitmap]
- clear_gdi2:
- invoke GdipDeleteGraphics,[hGraphics]
- clear_gdi3:
- ; Выключение GDI+
- invoke GdiplusShutdown,[gdiplusToken]
В приложении пример программы с исходным текстом, которая загружает изображение picture.jpg и выводит его в диалоговое окно. Вы можете заменить файл на свой, предварительно переименовав его, и посмотреть, как программа будет с ним работать.
Просмотров: 9158 | Комментариев: 8

Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье

ManHunter
(22.09.2015 в 10:41):
Странно, код в статью копировал прямо из исходника. Может манифесты какие-нибудь нужны или хз что.

addhaloka
(22.09.2015 в 09:31):
Там прозрачность вроде есть, а у picture с той же картинкой - белый фон: http://s1.bild.me/bilder/030315/5880687_0.png

ManHunter
(22.09.2015 в 07:59):
Если надо просто вывести изображение на форму, то код ничем не отличается от приведенного в статье. Shutter Count Viewer работает с PNG, там используется точно такой же код, можно посмотреть результат. А вот если хочется окно с неравномерными полупрозрачными регионами, то тут надо делать иначе. Я посмотрю, у меня где-то в закладках должна лежать ссылочка на пример.

addhaloka
(22.09.2015 в 07:45):
Спасибо, нужная вещь. Вот только никак не разберусь - как здесь (т . е. с минимальными усилиями с моей стороны)) сделать поддержку прозрачности в PNG? На wasm http://www.wasm.ru/forum/viewt...php?id=36909 нашлось кое-что на эту тему, но чёто с примером оттуда ходу не получается (зато код для загрузки из памяти очень понравился).

Grey
(27.07.2015 в 07:49):
Прошло))) Я тогда откуда то содрал код. Однако этот лаконичнее.

ManHunter
(24.07.2015 в 23:48):
Обещал же. Не прошло и полгода :) Или прошло?

Grey
(24.07.2015 в 09:58):
Спасибо.

Добавить комментарий
Заполните форму для добавления комментария

; Создать HBITMAP для установки на static
invoke GetSysColor,COLOR_BTNFACE
invoke GdipCreateHBITMAPFromBitmap,[xTmp],\
hBitmap,eax
Не знаю насколько это правильно, но результат тот, что нужен.