Что нового

Загрузить Bitmap из ресурсов и отобразить в Pic контроле

firex

AutoIT Гуру
Сообщения
943
Репутация
208
Код:
$hImage = _LoadResourceImage( _WinAPI_GetModuleHandle(0), Type, Name )
$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap( $hImage )
_GDIPlus_ImageDispose( $hImage )
; ---
$iCtrl = GUICtrlCreatePic( '', X, Y, W, H )
GUICtrlSetState( -1, $GUI_DISABLE )

$hObject = _SendMessage( GUICtrlGetHandle($iCtrl), 0x0172, 0, $hBitmap )
_WinAPI_DeleteObject( $hObject )

Func _LoadResourceImage($lri_instance, $sResType, $sResName)
	$hInfo = _WinAPI_FindResource($lri_instance, $sResType, $sResName)
	$hData = _WinAPI_LoadResource($lri_instance, $hInfo)
	$iSize = _WinAPI_SizeOfResource($lri_instance, $hInfo)
	$pData = _WinAPI_LockResource($hData)
	If @error Then
		Return SetError(1, 0, 0)
	EndIf
	$hMem = DllCall("kernel32.dll", "ptr", "GlobalAlloc", "uint", 2, "ulong_ptr", $iSize)
	If @error Then
		Return SetError(1, 0, 0)
	EndIf
	$pMem = DllCall("kernel32.dll", "ptr", "GlobalLock", "ptr", $hMem[0])
	If @error Then
		Return SetError(1, 0, 0)
	EndIf
	DllCall("kernel32.dll", "none", "RtlMoveMemory", "ptr", $pMem[0], "ptr", $pData, "ulong_ptr", $iSize)
	DllCall("kernel32.dll", "int", "GlobalUnlock", "ptr", $hMem[0])
	$hStream = _WinAPI_CreateStreamOnHGlobal($hMem[0])
	If @error Then
		Return SetError(1, 0, 0)
	EndIf
	_GDIPlus_Startup()
	$hImage = DllCall("gdiplus.dll", "uint", "GdipCreateBitmapFromStream", "ptr", $hStream, "ptr*", 0)
	If (@error) Or ($hImage[0]) Or (Not $hImage[2]) Then
		$hImage = 0
	EndIf
	_GDIPlus_Shutdown()
	DllCall("kernel32.dll", "ptr", "GlobalFree", "ptr", $hMem[0])
	If Not IsArray($hImage) Then
		Return SetError(1, 0, 0)
	EndIf
	Return $hImage[2]
EndFunc


Можно так.
Автор функции _LoadResourceImage - Yashied если не ошибаюсь.
 
Автор
V

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Всё равно не работает (Win 8 x64, Autoit 3.3.10.2)

Код:
$iPic = GUICtrlCreatePic('', 0, 0, 350, 70)

_GDIPlus_Startup()
$hImage = _LoadResourceImage(_WinAPI_GetModuleHandle(0), 2, 'Logo')
$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
_GDIPlus_ImageDispose($hImage)
_WinAPI_DeleteObject(_SendMessage( GUICtrlGetHandle($iPic), 0x0172, 0, $hBitmap ))
_GDIPlus_Shutdown()

...

Func _LoadResourceImage($hInstance, $sResType, $sResName, $iResLanguage = 0)

    Local $hInfo, $hData, $pData, $iSize, $hMem, $pMem, $hStream, $hImage

    If $iResLanguage Then
        $hInfo = _WinAPI_FindResourceEx($hInstance, $sResType, $sResName, $iResLanguage)
    Else
        $hInfo = _WinAPI_FindResource($hInstance, $sResType, $sResName)
    EndIf
    $hData = _WinAPI_LoadResource($hInstance, $hInfo)
    $iSize = _WinAPI_SizeOfResource($hInstance, $hInfo)
    $pData = _WinAPI_LockResource($hData)
    If @error Then
        Return SetError(1, 0, 0)
    EndIf
    $hMem = DllCall("kernel32.dll", "ptr", "GlobalAlloc", "uint", 2, "ulong_ptr", $iSize)
    If @error Then
        Return SetError(1, 0, 0)
    EndIf
    $pMem = DllCall("kernel32.dll", "ptr", "GlobalLock", "ptr", $hMem[0])
    If @error Then
        Return SetError(1, 0, 0)
    EndIf
    DllCall("kernel32.dll", "none", "RtlMoveMemory", "ptr", $pMem[0], "ptr", $pData, "ulong_ptr", $iSize)
    DllCall("kernel32.dll", "int", "GlobalUnlock", "ptr", $hMem[0])
    $hStream = _WinAPI_CreateStreamOnHGlobal($hMem[0])
    If @error Then
        Return SetError(1, 0, 0)
    EndIf
    _GDIPlus_Startup()
    $hImage = DllCall("gdiplus.dll", "uint", "GdipCreateBitmapFromStream", "ptr", $hStream, "ptr*", 0)
    If (@error) Or ($hImage[0]) Or (Not $hImage[2]) Then
        $hImage = 0
    EndIf
    _GDIPlus_Shutdown()
    DllCall("kernel32.dll", "ptr", "GlobalFree", "ptr", $hMem[0])
    If Not IsArray($hImage) Then
        Return SetError(1, 0, 0)
    EndIf
    Return $hImage[2]
EndFunc   ;==>_LoadResourceImage
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
Набросал пример, возможно вы делали что то не так:

http://rghost.ru/52336418
 

Ganibal95

GreenBytes
Сообщения
877
Репутация
240
Viktor1703
Для начало убедись что ресурс загружен и выдает его Handle.
Для преобразования из hImage в BitMap лучше использовать через DIB, нет потери яркости.
Код:
Func _GDIPlus_BitmapCreateDIBFromBitmap($hBitmap)

    Local $tBIHDR, $Ret, $tData, $pBits, $hResult = 0

    $Ret = DllCall($ghGDIPDll, 'uint', 'GdipGetImageDimension', 'ptr', $hBitmap, 'float*', 0, 'float*', 0)
    If (@error) Or ($Ret[0]) Then
        Return 0
    EndIf
    $tData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $Ret[2], $Ret[3], $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    $pBits = DllStructGetData($tData, 'Scan0')
    If Not $pBits Then
        Return 0
    EndIf
    $tBIHDR = DllStructCreate('dword;long;long;ushort;ushort;dword;dword;long;long;dword;dword')
    DllStructSetData($tBIHDR, 1, DllStructGetSize($tBIHDR))
    DllStructSetData($tBIHDR, 2, $Ret[2])
    DllStructSetData($tBIHDR, 3, $Ret[3])
    DllStructSetData($tBIHDR, 4, 1)
    DllStructSetData($tBIHDR, 5, 32)
    DllStructSetData($tBIHDR, 6, 0)
    $hResult = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBIHDR), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'dword', 0)
    If (Not @error) And ($hResult[0]) Then
        DllCall('gdi32.dll', 'dword', 'SetBitmapBits', 'ptr', $hResult[0], 'dword', $Ret[2] * $Ret[3] * 4, 'ptr', DllStructGetData($tData, 'Scan0'))
        $hResult = $hResult[0]
    Else
        $hResult = 0
    EndIf
    _GDIPlus_BitmapUnlockBits($hBitmap, $tData)
    Return $hResult
EndFunc   ;==>_GDIPlus_BitmapCreateDIBFromBitmap
 
Автор
V

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
firex [?]
Набросал пример, возможно вы делали что то не так:

Хм, да нет, изначально делал всё как надо, но после того как изображение не отобразилось на окне, меня это поставило в ступор, оказывается в версии AutoIt 3.3.10.2 наверное есть некий баг, из "Точечных рисунков" ресурс не грузится, а вот из "RCDATA" всё грузится нормально "опять ломают интерпретатор"
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Не нужно путать GDI битмап (Windows) с GDI+ битмапом. Это совершенно разные вещи и используются каждый со своей библиотекой.

GDI битмап обычно обозначается как HBITMAP и поддерживается всеми функциями API предназначенными для работы с графикой. HBITMAP может быть двух видов - Device-Dependent Bitmaps (DDB) и Device-Independent Bitmap (DIB). DDB привязан к текущей палитре (битности) экрана и содержит только цветовую информацию. DIB помимо цветов содержит еще и данные о его палитре. Таким образом DIB не зависит от текущего режима экрана. Ни о какой яркости здесь речь не идет. То, что находится в файле .bmp, является, естественно, DIB. Как правило в описании API функций указано, какой тип битмапа ей необходим. HBITMAP является нативным форматом для Windows.

GDI+ битмап используется только в пределах одноименной библиотеки. В отличии от GDI битмапа поддерживает прозрачность и множество других плюшек. Использовать GDI+ битмап в GDI нельзя, ровно как и наоборот. Отобразить напрямую GDI+ битмап на форме тоже нельзя, необходимо сначала преобразовать его в HBITMAP.

По поводу ресурсов. Тип ресурса BITMAP предназначен только для GDI битмапов, читай .bmp, и размещаются они в ресурсе в специальном формате. Любые другие изображения нужно помещать в RCDATA или собственный ресурс как есть, т.е. файл копируется целиком.

Viktor1703, если у тебя есть изображение в ресурсе BITMAP, то отобразить его на форме очень просто. Для этого достаточно лишь послать в окно следующее сообщение:

Код:
GUICtrlSendMsg($CtrlID, $STM_SETIMAGE, $IMAGE_BITMAP, $hBitmap)


Указатель получаем так (hInstance - текущий модуль, 100 - название ресурса с требуемым битмапом):

Код:
$hBitmap = _WinAPI_LoadBitmap($hInstance, 100)


Но для того, чтобы избежать утечек памяти, я рекомендую использовать следующую небольшую функцию:

Код:
#Region
#AutoIt3Wrapper_Res_File_Add=MyImage_400x400.bmp, 2, 100
#EndRegion

#Include <WinAPI.au3>

GUICreate('MyGUI', 400, 400)
GUICtrlCreatePic('', 0, 0, 400, 400)
$hPic = GUICtrlGetHandle(-1)
$hInstance = _WinAPI_GetModuleHandle('')
$hBitmap = _WinAPI_LoadBitmap($hInstance, 100)
_SetBitmap($hPic, $hBitmap)
GUISetState()

Do
Until GUIGetMsg() = -3

Func _SetBitmap($hWnd, $hBitmap, $fUpdate = 0)

	Local $hPrev

	$hPrev = _SendMessage($hWnd, 0x0172, 0, $hBitmap)
	If $hPrev Then
		_WinAPI_DeleteObject($hPrev)
	EndIf
	$hPrev = _SendMessage($hWnd, 0x0173)
	If $hPrev <> $hBitmap Then
		_WinAPI_DeleteObject($hBitmap)
	EndIf
	If $fUpdate Then
		_WinAPI_UpdateWindow($hWnd)
	EndIf
EndFunc   ;==>_SetBitmap
 
Автор
V

Viktor1703

AutoIT Гуру
Сообщения
1,535
Репутация
413
Ни чего не пойму.. пробовал тоже самое но с GUICtrlSendMsg, не получалось :scratch:
 
Верх