Blog. Just Blog

Вывод изображения на Ассемблере с помощью GDI+

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
При разработке своих программ пришлось столкнуться с задачей загрузки произвольного изображения из файла или из памяти и последующего вывода его в диалоговое окно. Есть несколько вариантов, как это сделать, но, на мой взгляд, наиболее корректный путь - воспользоваться функциями стандартной библиотеки GDI+. Она поддерживается всеми современными системами Windows, начиная с Windows XP и обладает очень широкими возможностями по обработке изображений.

Сперва в сегменте данных надо определить структуру GdiplusStartupInput, про которую FASM не знает. Да и в импорте тоже придется самостоятельно приписать несколько функций из библиотеки GDI+, так как в стандартных инклудах FASM их тоже нет. Описание остальных переменных, используемых в коде, вы можете посмотреть в прилагаемом к статье исходнике.
  1. ; Структура для работы с GDI+
  2. struct GdiplusStartupInput
  3.     GdiplusVersion           dd ?
  4.     DebugEventCallback       dd ?
  5.     SuppressBackgroundThread dd ?
  6.     SuppressExternalCodecs   dd ?
  7. ends
  8.  
  9. ; Размеры превьюшки
  10. IMG_X = 332
  11. IMG_Y = 248
  12.  
  13. ; ID статика для вывода изображения
  14. ID_IMG = 100
  15.  
  16. ; Имя файла для вывода на форму
  17. fname           db 'picture.jpg',0
Приведенный ниже код позволяет выводить на форму не только изображения в формате JPEG, но также BMP, PNG, GIF, ICO и других форматов, которые поддерживаются системой. Файл "picture.jpg" приведен только для примера. В реальных приложениях имя файла, естественно, будет другим. Размер и идентификатор STATIC для отображения картинки также будет меняться в зависимости от разрабатываемого приложения.

Теперь несколько слов о самом коде. Я постарался сделать его максимально универсальным, он не только выводит изображение на STATIC, но при этом подгоняет ее под размер этого поля, а также размещает изображение в центре. Если в вашем проекте подобные навороты не нужны, то можно оставить только загрузку и вывод изображения.
  1.         ; Инициализация GDI+
  2.         mov     [gdiplusSInput.GdiplusVersion],1
  3.         mov     [gdiplusSInput.DebugEventCallback],0
  4.         mov     [gdiplusSInput.SuppressBackgroundThread],0
  5.         mov     [gdiplusSInput.SuppressExternalCodecs],0
  6.         invoke  GdiplusStartup,gdiplusToken,gdiplusSInput,0
  7.  
  8.         ; Путь к файлу должен быть в юникоде
  9.         invoke  MultiByteToWideChar,CP_ACP,0,fname,\
  10.                 MAX_PATH*2,buff,MAX_PATH*2
  11.  
  12.         ; Создать битмап из файла
  13.         invoke  GdipCreateBitmapFromFile,buff,xTmp
  14.         or      eax,eax
  15.         jnz     clear_gdi3
  16.  
  17.         ; Изображение корректное?
  18.         invoke  GdipGetImageWidth,[xTmp],tmp
  19.         cmp     [tmp],0
  20.         je      clear_gdi2
  21.         invoke  GdipGetImageHeight,[xTmp],tmp
  22.         cmp     [tmp],0
  23.         je      clear_gdi2
  24.  
  25.         mov     [hBitmap],0
  26.  
  27.         ; Создать HBITMAP для установки на static
  28.         invoke  GdipCreateHBITMAPFromBitmap,[xTmp],\
  29.                 hBitmap,0x00FFFFFF
  30.         cmp     [hBitmap],0
  31.         jz      clear_gdi2
  32.  
  33.         ; Получить размеры изображения
  34.         invoke  GetObject,[hBitmap],sizeof.BITMAP,bm
  35.         or      eax,eax
  36.         jnz     @f
  37.  
  38.         invoke  GdipGetImageWidth,[xTmp],bm.bmWidth
  39.         invoke  GdipGetImageHeight,[xTmp],bm.bmHeight
  40.  
  41.         ; Изображение корректное?
  42.         cmp     [bm.bmWidth],0
  43.         jz      clear_gdi1
  44.         cmp     [bm.bmHeight],0
  45.         jz      clear_gdi1
  46. @@:
  47.         ; Создать виртуальный битмап для превьюшки
  48.         invoke  GetDC,NULL
  49.         invoke  CreateCompatibleBitmap,eax,IMG_X,IMG_Y
  50.         mov     [imgBitmap],eax
  51.         invoke  CreateCompatibleDC,NULL
  52.         mov     [hDC1],eax
  53.         invoke  CreateCompatibleDC,NULL
  54.         mov     [hDC2],eax
  55.         invoke  SelectObject,[hDC1],[imgBitmap]
  56.         mov     [hOld1],eax
  57.         invoke  SelectObject,[hDC2],[hBitmap]
  58.         mov     [hOld2],eax
  59.  
  60.         ; Размеры области заливки
  61.         mov     [rct.top],0
  62.         mov     [rct.left],0
  63.         mov     [rct.bottom],IMG_Y
  64.         mov     [rct.right],IMG_X
  65.  
  66.         ; Заливка фона виртуального битмапа
  67.         invoke  GetSysColorBrush,COLOR_BTNFACE
  68.         invoke  FillRect,[hDC1],rct,eax
  69.  
  70.         ; При необходимости подогнать большое изображение
  71.         ; под размер области превьюшки
  72.         mov     eax,[bm.bmWidth]
  73.         mov     [dImageWidth],eax
  74.         mov     eax,[bm.bmHeight]
  75.         mov     [dImageHeight],eax
  76.  
  77.         ; Размеры больше окна превьюшки?
  78.         cmp     [dImageWidth],IMG_X
  79.         ja      thumb_fix_size
  80.         cmp     [dImageHeight],IMG_Y
  81.         ja      thumb_fix_size
  82.  
  83.         ; Нарисовать как есть
  84.         jmp     thumb_draw
  85.  
  86. thumb_fix_size:
  87.         ; Пресчет размеров по горизонтали
  88.         mov     eax,[dImageWidth]
  89.         cmp     eax,[dImageHeight]
  90.         jb      @f
  91.  
  92.         mov     eax,[dImageHeight]
  93.         xor     edx,edx
  94.         mov     ecx,IMG_X
  95.         imul    ecx
  96.         xor     edx,edx
  97.         mov     ecx,[dImageWidth]
  98.         idiv    ecx
  99.         mov     [dImageHeight],eax
  100.         mov     [dImageWidth],IMG_X
  101.  
  102.         ; Пресчет размеров по вертикали
  103.         cmp     [dImageHeight],IMG_Y
  104.         jbe     thumb_draw
  105. @@:
  106.         mov     eax,[dImageWidth]
  107.         xor     edx,edx
  108.         mov     ecx,IMG_Y
  109.         imul    ecx
  110.         xor     edx,edx
  111.         mov     ecx,[dImageHeight]
  112.         idiv    ecx
  113.         mov     [dImageWidth],eax
  114.         mov     [dImageHeight],IMG_Y
  115.  
  116. thumb_draw:
  117.         ; Смещение по X
  118.         mov     eax,IMG_X
  119.         sub     eax,[dImageWidth]
  120.         shr     eax,1
  121.         mov     [ImageX],eax
  122.  
  123.         ; Смещение по Y
  124.         mov     eax,IMG_Y
  125.         sub     eax,[dImageHeight]
  126.         shr     eax,1
  127.         mov     [ImageY],eax
  128.  
  129.         ; Наложить изображение в центр виртуального битмапа
  130.         invoke  SetStretchBltMode,[hDC1],HALFTONE
  131.         invoke  StretchBlt,[hDC1],[ImageX],[ImageY],\
  132.                 [dImageWidth],[dImageHeight],[hDC2],0,0,\
  133.                 [bm.bmWidth],[bm.bmHeight],SRCCOPY
  134.  
  135.         invoke  SelectObject,[hDC1],[hOld1]
  136.         invoke  DeleteDC,[hDC1]
  137.         invoke  SelectObject,[hDC2],[hOld2]
  138.         invoke  DeleteDC,[hDC2]
  139.  
  140.         ; Установить виртуальный битмап на static
  141.         invoke  SendDlgItemMessage,[hwnddlg],ID_IMG,\
  142.                 STM_SETIMAGE,IMAGE_BITMAP,[imgBitmap]
  143.  
  144.         ; Освободить графику
  145.         invoke  GdipDisposeImage,[xTmp]
  146. clear_gdi1:
  147.         invoke  DeleteObject,[hBitmap]
  148. clear_gdi2:
  149.         invoke  GdipDeleteGraphics,[hGraphics]
  150. clear_gdi3:
  151.         ; Выключение GDI+
  152.         invoke  GdiplusShutdown,[gdiplusToken]
Конечно, это не единственный способ загрузки изображений из файлов. Например, это можно сделать с помощью OLE или WIC.

В приложении пример программы с исходным текстом, которая загружает изображение picture.jpg и выводит его в диалоговое окно. Вы можете заменить файл на свой, предварительно переименовав его, и посмотреть, как программа будет с ним работать.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

Picture.to.Form.Demo.GDIP.zip (188,680 bytes)


Поделиться ссылкой ВКонтакте
Просмотров: 9158 | Комментариев: 8

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

Комментарии

Отзывы посетителей сайта о статье
addhaloka (22.09.2015 в 15:24):
Ладно, буду копать тему, может со временем разберусь. :) Пока что такой костыль придумал:
        ; Создать HBITMAP для установки на static
        invoke GetSysColor,COLOR_BTNFACE
        invoke  GdipCreateHBITMAPFromBitmap,[xTmp],\
                hBitmap,eax
Не знаю насколько это правильно, но результат тот, что нужен.
ManHunter (22.09.2015 в 10:41):
Странно, код в статью копировал прямо из исходника. Может манифесты какие-нибудь нужны или хз что.
addhaloka (22.09.2015 в 09:31):
ЦитатаShutter Count Viewer работает с PNG, там используется точно такой же код, можно посмотреть результат.

Там прозрачность вроде есть, а у 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):
Спасибо.

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2025
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.08 сек. / MySQL: 2 (0.0112 сек.) / Память: 4.5 Mb
Наверх