Что нового

Объединение двух иконок в одну с сохранением прозрачности

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
Наконец-то я нашел "нормальный" способ сделать это. Проблема - сохранить прозрачность у объединенной иконки + разная глубина цвета у входных иконок. Здесь я убил сразу всех зайцев... Эта функция будет присутствовать в библиотеке WinAPEx, начиная с версии 3.2.

Код:
#Include <WinAPIEx.au3>

Opt('MustDeclareVars', 1)

Global Const $STM_SETIMAGE = 0x0172

Global $hIcon, $hOverlay, $hResult

; Create icon with overlay mask (48x48)
$hIcon = _WinAPI_ShellExtractIcon(@SystemDir & '\shell32.dll', 1, 48, 48)
If _WinAPI_GetVersion() >= '6.0' Then
	$hOverlay = _WinAPI_ShellExtractIcon(@SystemDir & '\imageres.dll', 154, 48, 48)
Else
	$hOverlay = _WinAPI_ShellExtractIcon(@SystemDir & '\shell32.dll', 29, 48, 48)
EndIf
$hResult = _WinAPI_AddIconOverlay($hIcon, $hOverlay)
_WinAPI_DestroyIcon($hIcon)
_WinAPI_DestroyIcon($hOverlay)

; Create GUI
GUICreate('MyGUI', 128, 128)
GUICtrlCreateIcon('', 0, 40, 40, 32, 32)
GUICtrlSendMsg(-1, $STM_SETIMAGE, 1, $hResult)
GUISetState()

Do
Until GUIGetMsg() = -3

; #FUNCTION# ====================================================================================================================
; Name...........: _WinAPI_AddIconOverlay
; Description....: Creates an icon by merging the source icon and overlay mask.
; Syntax.........: _WinAPI_AddIconOverlay ( $hIcon, $hOverlay )
; Parameters.....: $hIcon    - Handle to the source icon.
;                  $hOverlay - Handle to the icon to use as an overlay mask.
; Return values..: Success   - Handle to the newly created icon.
;                  Failure   - 0 and sets the @error flag to non-zero.
; Author.........: Yashied
; Modified.......:
; Remarks........: The source icon and overlay mask must be the same size but can have different bit depth. When you are finished
;                  using the icon, destroy it using the _WinAPI_DestroyIcon() function.
; Related........:
; Link...........: None
; Example........: Yes
; ===============================================================================================================================

Func _WinAPI_AddIconOverlay($hIcon, $hOverlay)

	Local $tSIZE, $Ret, $hIL, $hResult = 0

	$tSIZE = _WinAPI_GetIconDimension($hIcon)
	If @error Then
		Return SetError(1, 0, 0)
	EndIf
	$hIL = DllCall('comctl32.dll', 'ptr', 'ImageList_Create', 'int', DllStructGetData($tSIZE, 1), 'int', DllStructGetData($tSIZE, 1), 'uint', 0x0021, 'int', 2, 'int', 2)
	If (@error) Or (Not $hIL[0]) Then
		Return SetError(2, 0, 0)
	EndIf
	Do
		$Ret = DllCall('comctl32.dll', 'int', 'ImageList_ReplaceIcon', 'ptr', $hIL[0], 'int', -1, 'ptr', $hIcon)
		If (@error) Or ($Ret[0] = -1) Then
			ExitLoop
		EndIf
		$Ret = DllCall('comctl32.dll', 'int', 'ImageList_ReplaceIcon', 'ptr', $hIL[0], 'int', -1, 'ptr', $hOverlay)
		If (@error) Or ($Ret[0] = -1) Then
			ExitLoop
		EndIf
		$Ret = DllCall('comctl32.dll', 'int', 'ImageList_SetOverlayImage', 'ptr', $hIL[0], 'int', 1, 'int', 1)
		If (@error) Or (Not $Ret[0]) Then
			ExitLoop
		EndIf
		$Ret = DllCall('comctl32.dll', 'ptr', 'ImageList_GetIcon', 'ptr', $hIL[0], 'int', 0, 'uint', 0x00000100)
		If (@error) Or (Not $Ret[0]) Then
			ExitLoop
		EndIf
		$hResult = $Ret[0]
	Until 1
	DllCall('comctl32.dll', 'int', 'ImageList_Destroy', 'ptr', $hIL[0])
	If Not $hResult Then
		Return SetError(3, 0, 0)
	EndIf
	Return $hResult
EndFunc   ;==>_WinAPI_AddIconOverlay


И еще небольшое дополнение. Эта функция устанавливает прозрачность (делает бледнее) для указанной иконки.

Код:
#Include <WinAPIEx.au3>

Opt('MustDeclareVars', 1)

Global Const $STM_SETIMAGE = 0x0172

Global $hIcon = _WinAPI_ShellExtractIcon(@SystemDir & '\shell32.dll', 1, 32, 32)

GUICreate('MyGUI', 262, 108)
For $i = 0 To 3
	GUICtrlCreateIcon('', 0, 30 + 58 * $i, 38, 32, 32)
	GUICtrlSendMsg(-1, $STM_SETIMAGE, 1, _WinAPI_AddIconTransparency($hIcon, 100 - 25 * $i))
Next
_WinAPI_DestroyIcon($hIcon)
GUISetState()

Do
Until GUIGetMsg() = -3

; #FUNCTION# ====================================================================================================================
; Name...........: _WinAPI_AddIconTransparency
; Description....: Adds a transparency to the specified 32 bits-per-pixel icon.
; Syntax.........: _WinAPI_AddIconTransparency ( $hIcon [, $iPercent [, $fDelete]] )
; Parameters.....: $hIcon    - Handle to the icon.
;                  $iPercent - A value (in percent) that specifies how much to decrease the values of the alpha channel for the specified icon.
;                  $fDelete  - Specifies whether deletes an icon after the function is successful, valid values:
;                  |TRUE     - Icon will be deleted if the function succeeds.
;                  |FALSE    - Don't delete, you must release the icon when you are finished using it. (Default)
; Return values..: Success   - Handle to the newly created icon.
;                  Failure   - 0 and sets the @error flag to non-zero.
; Author.........: Yashied
; Modified.......:
; Remarks........: This function only works with 32 bits-per-pixel (RGB + Alpha) icons. When you are finished using the icon,
;                  destroy it using the _WinAPI_DestroyIcon() function.
; Related........:
; Link...........: None
; Example........: Yes
; ===============================================================================================================================

Func _WinAPI_AddIconTransparency($hIcon, $iPercent = 50, $fDelete = 0)

	Local $tICONINFO, $tBITMAP, $W, $H, $Ret, $iByte, $tBits, $pBits, $hBitmap[2], $hResult = 0

	$tICONINFO = DllStructCreate($tagICONINFO)
	$Ret = DllCall('user32.dll', 'int', 'GetIconInfo', 'ptr', $hIcon, 'ptr', DllStructGetPtr($tICONINFO))
	If (@error) Or (Not $Ret[0]) Then
		Return SetError(1, 0, 0)
	EndIf
	For $i = 0 To 1
		$hBitmap[$i] = DllStructGetData($tICONINFO, $i + 4)
	Next
	Do
		$tBITMAP = DllStructCreate($tagBITMAP)
		If Not _WinAPI_GetObject($hBitmap[1], DllStructGetSize($tBITMAP), DllStructGetPtr($tBITMAP)) Then
			ExitLoop
		EndIf
		$W = DllStructGetData($tBITMAP, 'bmWidth')
		$H = DllStructGetData($tBITMAP, 'bmHeight')
		$iByte = $W * $H * 4
		$tBits = DllStructCreate('byte[' & $iByte & ']')
		$pBits = DllStructGetPtr($tBits)
		If _WinAPI_GetBitmapBits($hBitmap[1], $iByte, $pBits) <> $iByte Then
			ExitLoop
		EndIf
		For $i = 1 To $iByte Step 4
			DllStructSetData($tBits, 1, DllStructGetData($tBits, 1, $i + 3) * $iPercent / 100, $i + 3)
		Next
		_WinAPI_DeleteObject($hBitmap[1])
		$hBitmap[1] = _WinAPI_CreateBitmap($W, $H, 1, 32, $pBits)
		If $hBitmap[1] Then
			$hResult = _WinAPI_CreateIconIndirect($hBitmap[1], $hBitmap[0])
		EndIf
	Until 1
	For $i = 0 To 1
		If $hBitmap[$i] Then
			_WinAPI_DeleteObject($hBitmap[$i])
		EndIf
	Next
	If Not $hResult Then
		Return SetError(1, 0, 0)
	EndIf
	If $fDelete Then
		_WinAPI_DestroyIcon($hIcon)
	EndIf
	Return $hResult
EndFunc   ;==>_WinAPI_AddIconTransparency
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,320
Yashied
Класс! :ok: :IL_AutoIt_1:
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
Последнее решение на эту тему было в библиотеке Icons.au3 (см. _SetCombineBkIcon()), но там иконки рисовались на заданном фоне, т.е. прозрачность у результирующей иконки отсутствовала как класс. У меня из за этого иногда возникали сложности при использовании таких иконок в ListView или TreeView... Сейчас совсем другое дело. Я это использовал в этом примере.

:smile:
 
Верх