Jump to content

Change colour of icon to greyscale?


mpower
 Share

Go to solution Solved by UEZ,

Recommended Posts

Hi is it possible to add a button to the below example that will toggle a change between the icon colour going from full colour to greyscale?

I.E. click button and icon becomes greyscale coloured, click button again it becomes full coloured.

#include <GUIConstantsEx.au3>
#include <WinAPI.au3>

$hGUI = GUICreate('Example', 200, 200)

$hButton = GUICtrlCreatePic('', 84, 84, 32, 32)
SetIcon($hButton, @ScriptDir & '\Icons.dll', 6, 32, 32)

GUISetState()

While 1
$msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Func SetIcon($hWnd, $sIcon, $iIndex, $iWidth, $iHeight)
    If Not IsHWnd($hWnd) Then
        $hWnd = GUICtrlGetHandle($hWnd)
    EndIf
    Local $hIcon = ShellExtractIcons($sIcon, $iIndex, $iWidth, $iHeight)
    Local $hBitmap, $hObj, $hDC, $hMem, $hSv
    $hDC = _WinAPI_GetDC($hWnd)
    $hMem = _WinAPI_CreateCompatibleDC($hDC)
    $hBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iWidth, $iHeight)
    $hSv = _WinAPI_SelectObject($hMem, $hBitmap)
    _WinAPI_DrawIconEx($hMem, 0, 0, $hIcon, $iWidth, $iHeight, 0, 0, 2)
    _WinAPI_ReleaseDC($hWnd, $hDC)
    _WinAPI_SelectObject($hMem, $hSv)
    _WinAPI_DeleteDC($hMem)
    _WinAPI_DestroyIcon($hIcon)
    _WinAPI_DeleteObject(MySendMsg($hWnd, 0x0172, 0, 0))
    MySendMsg($hWnd, 0x0172, 0, $hBitmap)
    $hObj = MySendMsg($hWnd, 0x0173)
    If $hObj <> $hBitmap Then
        _WinAPI_DeleteObject($hBitmap)
    EndIf
    Return 1
EndFunc   ;==>SetIcon

Func ShellExtractIcons($sIcon, $iIndex, $iWidth, $iHeight)
    Local $Ret = DllCall('shell32.dll', 'int', 'SHExtractIconsW', 'wstr', $sIcon, 'int', $iIndex, 'int', $iWidth, 'int', $iHeight, 'ptr*', 0, 'ptr*', 0, 'int', 1, 'int', 0)
    Return $Ret[5]
EndFunc   ;==>ShellExtractIcons

Func MySendMsg($hWnd, $iMsg, $wParam = 0, $lParam = 0, $iReturn = 0, $wParamType = "wparam", $lParamType = "lparam", $sReturnType = "lparam")
    Local $aResult = DllCall("user32.dll", $sReturnType, "SendMessage", "hwnd", $hWnd, "int", $iMsg, $wParamType, $wParam, $lParamType, $lParam)
    Return $aResult
EndFunc   ;==>SendMessage

Icons.zip

Link to comment
Share on other sites

You can try this (not fully 32-bit compatible):

#include <GUIConstantsEx.au3>
#include <GDIPlus.au3>
#include <WinAPIShellEx.au3>

_GDIPlus_Startup()
$hGUI = GUICreate('Example', 200, 200)
$hButton = GUICtrlCreatePic('', 84, 84, 32, 32)
SetIcon($hButton, @ScriptDir & '\Icons.dll', 6, 32, 32)

GUISetState()

$iState = -1

While 1
    Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            _GDIPlus_Shutdown()
            Exit
        Case $hButton
            _WinAPI_DeleteObject(GUICtrlSendMsg($hButton, 0x0172, $IMAGE_BITMAP, 0))
            $iState *= -1
            Switch $iState
                Case 1
                    SetIcon($hButton, @ScriptDir & '\Icons.dll', 6, 32, 32, True)
                Case -1
                    SetIcon($hButton, @ScriptDir & '\Icons.dll', 6, 32, 32, False)
            EndSwitch
    EndSwitch
WEnd

Func SetIcon($hWnd, $sIcon, $iIndex, $iWidth, $iHeight, $bGrey = False)
    Local $hIcon = _WinAPI_Create32BitHICON(_WinAPI_ShellExtractIcon($sIcon, $iIndex, $iWidth, $iHeight), True)
    Local $hHBitmap
    Local $hBmp = _GDIPlus_BitmapCreateFromHICON32($hIcon)
    ;_GDIPlus_ImageSaveToFile($hBmp, @ScriptDir & "\Test_Icon.png")
    $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmp)
    Switch $bGrey
        Case True
            Local $hIA = _GDIPlus_ImageAttributesCreate()
            Local $tColorMatrix = _GDIPlus_ColorMatrixCreateGrayScale()
            _GDIPlus_ImageAttributesSetColorMatrix($hIA, 1, True, $tColorMatrix)
            Local $hBmp_Grey = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
            Local $hGfx = _GDIPlus_ImageGetGraphicsContext($hBmp_Grey)
            _GDIPlus_GraphicsDrawImageRectRect($hGfx, $hBmp, 0, 0, $iWidth, $iHeight, 0, 0, $iWidth, $iHeight, $hIA)
            _WinAPI_DeleteObject($hHBitmap)
            $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmp_Grey)
            _GDIPlus_GraphicsDispose($hGfx)
            _GDIPlus_BitmapDispose($hBmp_Grey)
            _GDIPlus_ImageAttributesDispose($hIA)
    EndSwitch
    _GDIPlus_BitmapDispose($hBmp)
    _WinAPI_DestroyIcon($hIcon)
    _WinAPI_DeleteObject(GUICtrlSendMsg($hWnd, 0x0172, $IMAGE_BITMAP, $hHBitmap)) ;$STM_SETIMAGE = 0x0172
    _WinAPI_DeleteObject($hHBitmap)
    Return 1
EndFunc   ;==>SetIcon
Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

DrawState() could be used for building a solution for this Problem.

Here is an example without setting to pic button and repainting:

#include <GUIConstantsEx.au3>
#include <WinAPI.au3>

Global Const $DST_ICON = 0x03

Global Const $DSS_NORMAL = 0x00
Global Const $DSS_UNION = 0x10
Global Const $DSS_DISABLED = 0x20
Global Const $DSS_MONO = 0x80

Global $hGUI = GUICreate('Example', 200, 200)

Global $hDC = _WinAPI_GetDC($hGUI)
Global $ahIcon[5]
Global $ahBrush[5]
Global $aState[5] = [$DSS_NORMAL, $DSS_UNION, $DSS_DISABLED, $DSS_MONO, $DSS_MONO]

For $i = 0 To UBound($ahIcon) -1
    $ahIcon[$i] = ShellExtractIcons('Shell32.dll', 21, 32, 32)
Next

$ahBrush[0] = 0
$ahBrush[1] = 0
$ahBrush[2] = 0
$ahBrush[3] = _WinAPI_CreateSolidBrush(Random(0, 0xffffff))
$ahBrush[4] = _WinAPI_CreateSolidBrush(Random(0, 0xffffff))

GUISetState()


For $i = 0 To UBound($aState) -1
    _WinAPI_DrawState($hDC, $ahBrush[$i], $ahIcon[$i], 10 + 35 * $i, 10 + 35 * $i, 0, 0, BitOR($aState[$i], $DST_ICON))
Next

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Func ShellExtractIcons($sIcon, $iIndex, $iWidth, $iHeight)
    Local $Ret = DllCall('shell32.dll', 'int', 'SHExtractIconsW', 'wstr', $sIcon, 'int', $iIndex, 'int', $iWidth, 'int', $iHeight, 'ptr*', 0, 'ptr*', 0, 'int', 1, 'int', 0)
    Return $Ret[5]
EndFunc   ;==>ShellExtractIcons

Func _WinAPI_DrawState($hDC, $hBrush, $lData, $x, $y, $w, $h, $iFlags)
    Local $aRet = DllCall("User32.dll", "BOOL", "DrawState", "handle", $hDC, "handle", $hBrush, "ptr", 0, "long", $lData, "long", 0, _
            "int", $x, "int", $y, "int", $w, "int", $h, "UINT", $iFlags)

    If @error Then Return SetError(@error, @extended, False)
    Return $aRet[0]
EndFunc   ;==>_WinAPI_DrawState

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to comment
Share on other sites

Thanks for your responses guys, UEZ i do prefer yours as it does actually show the icon fully in greyscale. The example from funkey is good also but it doesnt achieve the visual effect I am after.

Now, it seems to work fine in the example you posed UEZ but when I try to apply it to my GUI it doesnt appear to work properly. It seems that the icons are not repainted for some reason.

I've attached my example to this post if you want to have a look at my application. Your code is added in "Ribbonsbar.au3".
 

Func _RibbonsBar_GrandButtons_Enable($Grandbutton_handle, $State)
    ;ConsoleWrite('_RibbonsBar_GrandButtons_Enable ...' & @CRLF)
    For $i = 1 To UBound($Bar_CreateGrandButton_Array)-1
        If $Bar_CreateGrandButton_Array[$i][0] == $Grandbutton_handle Then
            If $State = 1 Then
                GUICtrlSetState($Bar_CreateGrandButton_Array[$i][5], $GUI_ENABLE)
                GUICtrlSetState($Bar_CreateGrandButton_Array[$i][6], $GUI_ENABLE)
                __RibbonsBar_SetIconAlpha($Bar_CreateGrandButton_Array[$i][11], $GrandIcons_DLL, $Bar_CreateGrandButton_Array[$i][15], 32, 32)
            ElseIf $State = 0 Then
                GUICtrlSetState($Bar_CreateGrandButton_Array[$i][5], $GUI_DISABLE)
                GUICtrlSetState($Bar_CreateGrandButton_Array[$i][6], $GUI_DISABLE)
                __RibbonsBar_SetIconGreyscale($Bar_CreateGrandButton_Array[$i][11], $GrandIcons_DLL, $Bar_CreateGrandButton_Array[$i][15], 32, 32, True)
            EndIf
            ExitLoop
        EndIf
    Next
EndFunc ;==>_RibbonsBar_GrandButtons_Enable

Func __RibbonsBar_SetIconGreyscale($hWnd, $sIcon, $iIndex, $iWidth, $iHeight, $bGrey = False)
    Local $hIcon = _WinAPI_Create32BitHICON(__RibbonsBar_ShellExtractIcons($sIcon, $iIndex, $iWidth, $iHeight), True)
    Local $hHBitmap
    Local $hBmp = _GDIPlus_BitmapCreateFromHICON32($hIcon)
    $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmp)
    Switch $bGrey
        Case True
            Local $hIA = _GDIPlus_ImageAttributesCreate()
            Local $tColorMatrix = _GDIPlus_ColorMatrixCreateGrayScale()
            _GDIPlus_ImageAttributesSetColorMatrix($hIA, 1, True, $tColorMatrix)
            Local $hBmp_Grey = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight)
            Local $hGfx = _GDIPlus_ImageGetGraphicsContext($hBmp_Grey)
            _GDIPlus_GraphicsDrawImageRectRect($hGfx, $hBmp, 0, 0, $iWidth, $iHeight, 0, 0, $iWidth, $iHeight, $hIA)
            _WinAPI_DeleteObject($hHBitmap)
            $hHBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmp_Grey)
            _GDIPlus_GraphicsDispose($hGfx)
            _GDIPlus_BitmapDispose($hBmp_Grey)
            _GDIPlus_ImageAttributesDispose($hIA)
    EndSwitch
    _GDIPlus_BitmapDispose($hBmp)
    _WinAPI_DestroyIcon($hIcon)
    _WinAPI_DeleteObject(GUICtrlSendMsg($hWnd, 0x0172, $IMAGE_BITMAP, 0))
    _WinAPI_DeleteObject(GUICtrlSendMsg($hWnd, 0x0172, $IMAGE_BITMAP, $hHBitmap)) ;$STM_SETIMAGE = 0x0172
    _WinAPI_DeleteObject($hHBitmap)
    Return 1
EndFunc   ;==>SetIcon

The attached example includes the DLL files for icons and also the includes that I have used in my example.

example.zip

Link to comment
Share on other sites

Hi UEZ, thanks for helping!

I am using Win7 64bit and also have a 32bit Win 7 machine to test compatibility. Both seem to behave the same way:

Initial app start - looks great:

12uqG.png

I click the Redo button to disable all the buttons - essentially disable the control and change icon to greyscale colour and I get below:

usARq.png

If I then put my mouse over an icon it gets drawn... :

IYaET.png

mulO.png

Also side note: if you notice, the greyscale icons dont appear to have a transparent bg...for example the Expoort icon, it full colour it has a transparent bg, in greyscale it doesnt.

Edited by mpower
Link to comment
Share on other sites

  • Solution

Ok, got it. Just use _WinAPI_RedrawWindow($maingui) to refresh the icons.
 

Case $SmallButton_Undo
            _RibbonsBar_GrandButtons_Enable($hGrandButton_New, 1)
            _RibbonsBar_GrandButtons_Enable($hGrandButton_Save, 1)
            _RibbonsBar_GrandButtons_Enable($hGrandButton_Export, 1)
            _RibbonsBar_GrandButtons_Enable($hGrandButton_AddItems, 1)
            _RibbonsBar_GrandButtons_Enable($hGrandButton_DelItems, 1)
            _RibbonsBar_GrandButtons_Enable($hGrandButton_Open, 1)
            If _RibbonsBar_SmallButtons_GetState($SmallButton_Undo) = 1 Then
                ConsoleWrite('undo...'&@CRLF)
            EndIf
            _WinAPI_RedrawWindow($maingui)
        Case $SmallButton_Redo
            _RibbonsBar_GrandButtons_Enable($hGrandButton_New, 0)
            _RibbonsBar_GrandButtons_Enable($hGrandButton_Save, 0)
            _RibbonsBar_GrandButtons_Enable($hGrandButton_Export, 0)
            _RibbonsBar_GrandButtons_Enable($hGrandButton_AddItems, 0)
            _RibbonsBar_GrandButtons_Enable($hGrandButton_DelItems, 0)
            _RibbonsBar_GrandButtons_Enable($hGrandButton_Open, 0)
            If _RibbonsBar_SmallButtons_GetState($SmallButton_Redo) = 1 Then
                ConsoleWrite('redo...'&@CRLF)
            EndIf
            _WinAPI_RedrawWindow($maingui)
        Case $hTab_Home

As I already said the icon extraction doesn't seems to support 100% 32-bit alpha channel. I don't know why!

Br,

UEZ

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...