Вывод изображения на Ассемблере с помощью WIC
На сайте уже есть две статьи про загрузку и вывод изображения с помощью GDI+ и OLE, сегодня расскажу про еще очередной способ загрузки изображений, на этот раз с помощью WIC (Windows Imaging Component). Эта технология позволяет не привязываться к конкретным форматам изображений, а делегировать большую часть рутинной работы системе. Если установлен соответствующий графический кодек и система в принципе может открыть изображение во встроенном Просмотрщике фотографий, значит его можно будет прочитать и при помощи Windows Imaging Component. Например, популярный формат WebP в чистой Windows 7 не открывается, но если поставить кодеки, то все сразу заработает.Переходим к программированию. Поскольку это COM-технология, то нам понадобится описание множества GUID, констант и интерфейсов. Надо ли говорить, что FASM про них ничего не знает? А множество действительно внушительное.
Code (Assembler) : Убрать нумерацию
- ; GUID {CACAF262-9370-4615-A13B-9F5539DA4C0A}
- CLSID_WICImagingFactory dd 0CACAF262h
- dw 09370h
- dw 04615h
- db 0A1h, 03Bh, 09Fh, 055h, 039h, 0DAh, 04Ch, 00Ah
- ; GUID {EC5EC8A9-C395-4314-9C77-54D7A935FF70}
- IID_IWICImagingFactory dd 0EC5EC8A9h
- dw 0C395h
- dw 04314h
- db 09Ch, 077h, 054h, 0D7h, 0A9h, 035h, 0FFh, 070h
- ; IID_IWICImagingFactory Interface
- struct IWICImagingFactory
- ; IUnknown
- QueryInterface dd ? ; 000h
- AddRef dd ? ; 004h
- Release dd ? ; 008h
- ; IWICImagingFactory
- CreateDecoderFromFilename dd ? ; 00Ch
- CreateDecoderFromStream dd ? ; 010h
- CreateDecoderFromFileHandle dd ? ; 014h
- CreateComponentInfo dd ? ; 018h
- CreateDecoder dd ? ; 01Ch
- CreateEncoder dd ? ; 020h
- CreatePalette dd ? ; 024h
- CreateFormatConverter dd ? ; 028h
- CreateBitmapScaler dd ? ; 02Ch
- CreateBitmapClipper dd ? ; 030h
- CreateBitmapFlipRotator dd ? ; 034h
- CreateStream dd ? ; 038h
- CreateColorContext dd ? ; 03Ch
- CreateColorTransformer dd ? ; 040h
- CreateBitmap dd ? ; 044h
- CreateBitmapFromSource dd ? ; 048h
- CreateBitmapFromSourceRect dd ? ; 04Ch
- CreateBitmapFromMemory dd ? ; 050h
- CreateBitmapFromHBITMAP dd ? ; 054h
- CreateBitmapFromHICON dd ? ; 058h
- CreateComponentEnumerator dd ? ; 05Ch
- CreateFastMetadataEncoderFromDecoder dd ? ; 060h
- CreateFastMetadataEncoderFromFrameDecode dd ? ; 064h
- CreateQueryWriter dd ? ; 068h
- CreateQueryWriterFromReader dd ? ; 06Ch
- ends
- ; IID_IWICBitmapDecoder Interface
- struct IWICBitmapDecoder
- ; IUnknown
- QueryInterface dd ? ; 000h
- AddRef dd ? ; 004h
- Release dd ? ; 008h
- ; IWICBitmapDecoder
- QueryCapability dd ? ; 00Ch
- Initialize dd ? ; 010h
- GetContainerFormat dd ? ; 014h
- GetDecoderInfo dd ? ; 018h
- CopyPalette dd ? ; 01Ch
- GetMetadataQueryReader dd ? ; 020h
- GetPreview dd ? ; 024h
- GetColorContexts dd ? ; 028h
- GetThumbnail dd ? ; 02Ch
- GetFrameCount dd ? ; 030h
- GetFrame dd ? ; 034h
- ends
- ; IWICBitmapFrameDecode Interface
- struct IWICBitmapFrameDecode
- ; IUnknown
- QueryInterface dd ? ; 000h
- AddRef dd ? ; 004h
- Release dd ? ; 008h
- ; IWICBitmapFrameDecode
- GetSize dd ? ; 00Ch
- GetPixelFormat dd ? ; 010h
- GetResolution dd ? ; 014h
- CopyPalette dd ? ; 018h
- CopyPixels dd ? ; 01Ch
- GetMetadataQueryReader dd ? ; 020h
- GetColorContexts dd ? ; 024h
- GetThumbnail dd ? ; 028h
- ends
- ; IID_IWICFormatConverter Interface
- struct IWICFormatConverter
- ; IUnknown
- QueryInterface dd ? ; 000h
- AddRef dd ? ; 004h
- Release dd ? ; 008h
- ; IWICFormatConverter
- GetSize dd ? ; 00Ch
- GetPixelFormat dd ? ; 010h
- GetResolution dd ? ; 014h
- CopyPalette dd ? ; 018h
- CopyPixels dd ? ; 01Ch
- Initialize dd ? ; 020h
- CanConvert dd ? ; 024h
- ends
- ; IID_IWICBitmap Interface
- struct IWICBitmap
- ; IUnknown
- QueryInterface dd ? ; 000h
- AddRef dd ? ; 004h
- Release dd ? ; 008h
- ; IWICBitmap
- GetSize dd ? ; 00Ch
- GetPixelFormat dd ? ; 010h
- GetResolution dd ? ; 014h
- CopyPalette dd ? ; 018h
- CopyPixels dd ? ; 01Ch
- Lock dd ? ; 020h
- SetPalette dd ? ; 024h
- SetResolution dd ? ; 028h
- ends
- ; IID_IWICBitmapLock Interface
- struct IWICBitmapLock
- ; IUnknown
- QueryInterface dd ? ; 000h
- AddRef dd ? ; 004h
- Release dd ? ; 008h
- ; IWICBitmapLock
- GetSize dd ? ; 00Ch
- GetStride dd ? ; 010h
- GetDataPointer dd ? ; 014h
- GetPixelFormat dd ? ; 018h
- ends
- ; GUID {6FDDC324-4E03-4BFE-B185-3D77768DC910}
- GUID_WICPixelFormat32bppPBGRA dd 06FDDC324h
- dw 04E03h
- dw 04BFEh
- db 0B1h, 085h, 03Dh, 077h, 076h, 08Dh, 0C9h, 010h
- CLSCTX_INPROC_SERVER = 0x01
- WICBitmapDitherTypeNone = 0x00000000
- WICBitmapPaletteTypeCustom = 0x00000000
- WICBitmapCacheOnDemand = 0x00000001
- WICBitmapLockWrite = 0x00000002
- WICDecodeMetadataCacheOnDemand = 0x00000000
Затем надо создать декодер изображения, объект типа IWICBitmapDecoder. Для этого на фабрике есть несколько разных методов интерфейса, самым универсальным будет метод CreateDecoderFromFilename. Он как раз позволяет не заморачиваться с определением формата, а поручить всю грязную работу системе. В этом случае одним кодом можно открывать картинки разных форматов. Если на этом этапе объект декодера создать не удалось, то значит система не поддерживает этот формат и надо попросить пользователя установить соответствующие кодеки или сделать это самостоятельно, все зависит от приложения. Если объект декодера создан, то практически со 100% вероятностью дальше все будет работать как надо.
Code (Assembler) : Убрать нумерацию
- ; Инициализация фабрики
- invoke CoCreateInstance,CLSID_WICImagingFactory,NULL,\
- CLSCTX_INPROC_SERVER,IID_IWICImagingFactory,pFactory
- ; Создать декодер
- mov eax, [pFactory]
- mov eax, [eax]
- stdcall dword [eax+IWICImagingFactory.CreateDecoderFromFilename],\
- [pFactory],\
- buff,\
- NULL,\
- GENERIC_READ,\
- WICDecodeMetadataCacheOnDemand,\
- pDecoder
- cmp eax,0
- ; Формат файла не поддерживается
- jne loc_clear
Code (Assembler) : Убрать нумерацию
- ; Получить первый фрейм
- mov eax, [pDecoder]
- mov eax, [eax]
- stdcall dword [eax+IWICBitmapDecoder.GetFrame],[pDecoder],\
- 0,\
- pSource
Code (Assembler) : Убрать нумерацию
- ; Создать конвертер
- mov eax, [pFactory]
- mov eax, [eax]
- stdcall dword [eax+IWICImagingFactory.CreateFormatConverter],[pFactory],\
- pConverter
- ; Инициализировать конвертер
- mov eax, [pConverter]
- mov eax, [eax]
- stdcall dword [eax+IWICFormatConverter.Initialize],[pConverter],\
- [pSource],\
- GUID_WICPixelFormat32bppPBGRA,\
- WICBitmapDitherTypeNone,\
- NULL,\
- 0,0,\
- WICBitmapPaletteTypeCustom
- ; Создать битмап из фрейма
- mov eax, [pFactory]
- mov eax, [eax]
- stdcall dword [eax+IWICImagingFactory.CreateBitmapFromSource],[pFactory],\
- [pConverter],\
- WICBitmapCacheOnDemand,\
- pBitmap
Code (Assembler) : Убрать нумерацию
- ; Получить размер фрейма
- mov eax, [pSource]
- mov eax, [eax]
- stdcall dword [eax+IWICBitmapFrameDecode.GetSize],[pSource],\
- rcLock.right,\
- rcLock.bottom
- ; Получить данные битмапа
- mov eax, [pBitmap]
- mov eax, [eax]
- stdcall dword [eax+IWICBitmap.Lock],[pBitmap],\
- rcLock,\
- WICBitmapLockWrite,\
- pLock
- ; Размер и указатель на данные
- mov eax, [pLock]
- mov eax, [eax]
- stdcall dword [eax+IWICBitmapLock.GetDataPointer],[pLock],\
- BufferSize,\
- BufferData
Code (Assembler) : Убрать нумерацию
- ; Создать HBITMAP из WICBitmap
- invoke CreateBitmap,[rcLock.right],[rcLock.bottom],1,32,[BufferData]
- mov [hBitmap],eax
В приложении пример программы с исходным текстом, которая загружает изображение из файла picture.webp и выводит его в диалоговое окно. Для корректной работы необходимо установить кодеки, ссылка на дистрибутив дана в первом абзаце.
Просмотров: 911 | Комментариев: 5
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(17.01.2023 в 12:37):
У IrfanView используется свой декодер, а тут просто вызываются системные функции. Если сама система не может отобразить картинку, то программа и подавно.
Андрей
(03.01.2023 в 19:35):
В первом абзаце верно указано, что программа открывает все изображения, которые можно просмотреть встроенным Просмотрщиком. У меня WinXP(SP3). Мой Просмотрщик не видит формат WebP. Все другие форматы ваша программа открыла. Скорее всего моя ОС по какой-то причине не может воспользоваться установленным кодеком.
ManHunter
(03.01.2023 в 15:29):
Minimum supported client : Windows XP with SP2, Windows Vista
Minimum supported server : Windows Server 2008
Minimum supported server : Windows Server 2008
Андрей
(03.01.2023 в 15:09):
На Win XP при наличии кодека программа открывает пустое диалоговое окно без изображения. Хотя файлы в формате WebP на Win XP открывает программа IrfanView. Кодек установлен в каталог "Program Files\WebP Codec".
кодер
(14.08.2022 в 13:41):
Спасибо за очередную толковую статью по низкоуровнему программированию под Windows!
Добавить комментарий
Заполните форму для добавления комментария