Blog. Just Blog

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

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Ранее я уже разбирал загрузку и вывод изображения с помощью GDI+, но это далеко не единственный способ загрузки изображения из файла. В дополнение к этой теме предлагаю рассмотреть еще один способ, как можно загрузить изображение из файла средствами OLE. Сперва пропишем GUID объекта IID_IPicture и создадим структуру для методов интерфейса IPicture. В MSDN методы перечислены в алфавитном порядке, а не так, как они фактически идут в интерфейсе, имейте это в виду.
  1. ; GUID {7BF80980-BF32-101A-8BBB-00AA00300CAB}
  2. IID_IPicture       dd 7BF80980h
  3.                    dw 0BF32h
  4.                    dw 0101Ah
  5.                    db 08Bh, 0BBh, 0h, 0AAh, 0h, 030h, 00Ch, 0ABh
  6.  
  7. ; IPicture Interface
  8. struct IPicture
  9.     ; IUnknown
  10.     QueryInterface dd ?
  11.     AddRef         dd ?
  12.     Release        dd ?
  13.  
  14.     ; IPicture
  15.     get_Handle     dd ?
  16.     get_hPal       dd ?
  17.     get_Type       dd ?
  18.     get_Width      dd ?
  19.     get_Height     dd ?
  20.     Render         dd ?
  21.     set_hPal       dd ?
  22.     get_CurDC      dd ?
  23.     SelectPicture  dd ?
  24.     get_KeepOriginalFormat dd ?
  25.     set_KeepOriginalFormat dd ?
  26.     PictureChanged dd ?
  27.     SaveAsFile     dd ?
  28.     get_Attributes dd ?
  29.     SetHdc         dd ?
  30. ends
Итак, у нас есть файл с изображением, который надо загрузить в память и затем выполнить с ним нужные действия, например, вывести на форму. Первым делом загружаем его целиком в память.
  1.         ; Прочитать файл в память
  2.         invoke  _lopen,fname,OF_READ
  3.         cmp     eax,-1
  4.         je      loc_free_1
  5.         mov     ebx,eax
  6.  
  7.         ; Получить размер файла
  8.         invoke  GetFileSize,ebx,NULL
  9.         mov     [file_size],eax
  10.  
  11.         ; Выделить память под файл
  12.         invoke  GetProcessHeap
  13.         mov     [hProcHeap],eax
  14.         invoke  HeapAlloc,[hProcHeap],0,[file_size]
  15.         mov     [hLock],eax
  16.  
  17.         ; Загрузить картинку в память
  18.         invoke  _lread,ebx,[hLock],[file_size]
  19.         invoke  _lclose,ebx
Тут ничего сложного, в куче выделяется блок памяти под размер файла картинки, затем в него считывается содержимое файла.

Теперь вступают в дело функции OLE. При помощи функции CreateStreamOnHGlobal из блока памяти по его хэндлу формируется поток, а из этого потока функцией OleLoadPicture создается объект картинки, с которым мы дальше будем работать. Важное замечание: функция OleLoadPicture работает только с изображениями в формате JPEG, GIF, BMP, ICO, WMF и EMF. Формат PNG не поддерживается.
  1.         ; Создать поток из данных
  2.         invoke  CreateStreamOnHGlobal,[hLock],TRUE,iStream
  3.  
  4.         ; Загрузить картинку из памяти
  5.         invoke  OleLoadPicture,[iStream],0,TRUE,IID_IPicture,iPicture
После создания объекта iPicture мы можем воспользоваться его методами, чтобы работать с изображением. Во-первых, получим хэндл битмапа при помощи метода get_Handle. Во-вторых, нам надо получить размеры изображения. Тут можно воспользоваться уже известной нам функцией GDI GetObject, но раз уж мы используем объект OLE, то давайте сделаем это его методами.
  1.         ; Вызвать метод интерфейса IPicture->get_Handle()
  2.         mov     eax, [iPicture]
  3.         mov     eax, [eax]
  4.         stdcall dword [eax+IPicture.get_Handle],[iPicture],hBitmap
  5.         ; Хэндл изображения
  6.         mov     eax,[hBitmap]
  7.  
  8.         ; Вызвать метод интерфейса IPicture->get_Width()
  9.         mov     eax, [iPicture]
  10.         mov     eax,[eax]
  11.         stdcall dword [eax+IPicture.get_Width],[iPicture],bm.bmWidth
  12.         ; Количество пикселей на логический дюйм по горизонтали
  13.         invoke  GetDC,NULL
  14.         invoke  GetDeviceCaps,eax,LOGPIXELSX
  15.         ; Пересчитать HIMETRIC в обычные пикселы
  16.         mov     ecx,[bm.bmWidth]
  17.         xor     edx,edx
  18.         imul    ecx
  19.         mov     ecx,HIMETRIC_PER_INCH
  20.         idiv    ecx
  21.         ; Ширина изображения
  22.         mov     [bm.bmWidth],eax
  23.  
  24.         ; Вызвать метод интерфейса IPicture->get_Height()
  25.         mov     eax, [iPicture]
  26.         mov     eax, [eax]
  27.         stdcall dword [eax+IPicture.get_Height],[iPicture],bm.bmHeight
  28.         ; Количество пикселей на логический дюйм по вертикали
  29.         invoke  GetDC,NULL
  30.         invoke  GetDeviceCaps,eax,LOGPIXELSY
  31.         ; Пересчитать HIMETRIC в обычные пикселы
  32.         mov     ecx,[bm.bmHeight]
  33.         xor     edx,edx
  34.         imul    ecx
  35.         mov     ecx,HIMETRIC_PER_INCH
  36.         idiv    ecx
  37.         ; Высота изображения
  38.         mov     [bm.bmHeight],eax
Тут есть одна важная особенность. Методы get_Width и get_Height возвращают размеры изображения не в привычных нам пикселах, а в условных единицах HIMETRIC, то есть в сотых долях миллиметра, зависящих от установленного разрешения экрана. Для перевода этого значения в пикселы надо умножить его на логические дюймы, возвращаемые функцией GetDeviceCaps, а затем поделить на константу 2540, это количество пикселов в дюйме. Вот и все, у нас есть загруженный битмап, есть его хэндл и есть размеры изображения. Этих данных достаточно, чтобы сделать с картинкой что угодно, в нашем случае это просто отмасштабировать ее до нужных размеров и вывести на форму.

Поскольку функция CreateStreamOnHGlobal работает с блоками памяти, это дает нам возможность загружать картинки не только из файла на диске, но и напрямую из памяти. Допустим, что файл с картинкой хранится где-то в сегменте данных.
  1. ; Данные картинки для вывода на форму
  2. image_data:
  3. file 'image.jpg'
  4. data_size=$-image_data
В этом случае нам надо также выделить блок памяти в куче, равный размеру хранимых данных, затем скопировать в него содержимое картинки. Далее все без изменений, по хэндлу блока памяти создаем поток, из него создаем объект с картинкой.
  1.         ; Выделить память под картинку
  2.         invoke  GetProcessHeap
  3.         mov     [hProcHeap],eax
  4.         invoke  HeapAlloc,[hProcHeap],0,data_size
  5.         mov     [hLock],eax
  6.  
  7.         ; Скопировать картинку в выделенную память
  8.         mov     esi,image_data
  9.         mov     edi,[hLock]
  10.         mov     ecx,data_size
  11.         rep     movsb
  12.  
  13.         ; Создать поток из данных
  14.         invoke  CreateStreamOnHGlobal,[hLock],TRUE,iStream
Для полноты картины давайте разберем еще загрузку изображения из ресурсов. При помощи функций FindResource и LoadResource находим нужный нам ресурс в нашем или стороннем модуле, функция SizeofResource вернет его размер, а LockResource - указатель на данные картинки в памяти. После этого, как и при загрузке изображения из предыдущего примера, выделяем память в куче и копируем туда данные из ресурсов. Остальной код без изменений.
  1.         ; Загрузить картинку из ресурсов
  2.         invoke  FindResource,NULL,1,RT_RCDATA
  3.         mov     ebx,eax
  4.         invoke  SizeofResource,NULL,eax
  5.         mov     [file_size],eax
  6.         invoke  LoadResource,NULL,ebx
  7.         mov     ebx,eax
  8.  
  9.         ; Выделить память под картинку
  10.         invoke  GetProcessHeap
  11.         mov     [hProcHeap],eax
  12.         invoke  HeapAlloc,[hProcHeap],0,[file_size]
  13.         mov     [hLock],eax
  14.  
  15.         ; Скопировать картинку в выделенную память
  16.         invoke  LockResource,ebx
  17.         mov     esi,eax
  18.         mov     edi,[hLock]
  19.         mov     ecx,[file_size]
  20.         rep     movsb
  21.  
  22.         ; Создать поток из данных
  23.         invoke  CreateStreamOnHGlobal,[hLock],TRUE,iStream
Если там вам интересна, то посмотрите еще один способ вывести картинку на форму - с использованием WIC (Windows Imaging Component).

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

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

Picture.to.Form.Demo.OLE.zip (392,545 bytes)


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

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

Комментарии

Отзывы посетителей сайта о статье
Комментариeв нет

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

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

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