Jump to content



Photo

IconImage UDF


  • Please log in to reply
33 replies to this topic

#1 Ward

Ward

    Adventurer

  • Active Members
  • PipPip
  • 143 posts

Posted 17 September 2011 - 03:56 PM

"ICONIMAGE" is a binary struct defined by Microsoft for saving an single icon (See this article in msdn).
This UDF is basically for icon management, it takes ICONIMAGE as an binary intermediary to handle icons.
With this UDF, you can:
  • Load, save, and convert icon in any size, any format, even can handle Vista PNG icon under Windows XP.
    Supported icon format: standard or PNG .ico, .png file, or other image files (.bmp/.jpg etc).
    Source and destination can be files or binary data.

  • Get system associated icon for any files, folders, even links (partial based on _GetIconForFile by WideBoyDixon).
  • Load icons from windows PE files (EXE or DLL).
  • Convert system icon handle or GDI+ image handle from/to icon.
  • Merge/Rotate/Flip icons.
  • Icon cache or script embed icon can be easily realized by this UDF.
This UDF need GDI+ for most image conversion.

Other required UDF (not included) is my Binary UDF and Yashied's WinAPIEx UDF.
The example script also need Yashied's ICON UDF for display icon.

Functions List
Spoiler


Screenshots of Example
Spoiler


Because icon handle is always device dependent. So this UDF should only works on 32bit color device for now. I think most modern system support that. I already do a lot of effort for alpha channel support and test under Windows 7 and Windows XP. But deal with images what system not supported is a painful work. If there still any problem, please tell me. Thanks.

Attached File  IconImage.zip   11.26KB   202 downloads

2011/09/12 Update Note:
  • Add multiple icon support (both loading and saving).
  • Image scale now support specific quality. Quality flag is defined as $GDIP_ModeXXXX.
  • Fix a lot of bugs in handling alpha channel icons and PNG icons. Now even better than Windows 7 does.
  • Update the example script.
Attached File  IconImage.zip   12.56KB   604 downloads

Edited by Ward, 22 September 2011 - 10:44 AM.








#2 Beege

Beege

    Universalist

  • MVPs
  • 843 posts

Posted 17 September 2011 - 08:42 PM

Ward,
Nice UDF! One thing though, APIConstants.au3 for Yashieds WinAPIEx.au3 is no longer automatically included in his UDF so

#include "APIConstants.au3"

needs to be added somewhere in order to get your example to work. Very nice example to btw :graduated:

#3 asdf8

asdf8

    Wayfarer

  • Active Members
  • Pip
  • 67 posts

Posted 17 September 2011 - 09:56 PM

Ward,
please tell me why the picture does not appear in the code:
AutoIt         
#Include <GUIConstantsEx.au3> #Include "IconImage.au3" #Include "Icons.au3"   $PngData = Binary("0x89504E470D0A1A0A0000000D4948445200000020000000200806000000737A7AF40000000774494D4507DB09110A1E38A04C16500000001774455874536F66747761726500474C44504E472076657220332E347185A4E10000000874704E47474C4433000000004A80291F0000000467414D410000B18F0BFC61050000052A49444154789CBD567D4C535714EFD22C8430C287422163306C4A81D282514216C1022D6C6612E66620CCB1691808A271CB46661495F24D1C9B732A31C010D02963080A2DD00D418110686636704ED8F816F9DCC8B21092FD7376CEE33EF3A6684B68FCE3E4BE7BDFBBE7F73B9FEF8800E085678948247A519363B8AECD6D057CB631F7FD5A45640101FBC89C1628ED79006A5DB3D5493C41606B4AB193FA64539D3ACBF00F01AA752DB0EDB81EAA4CD350F8E32844645B97C42302A8541C96D9509456D603E5B74740FFEB3CB4DCFF0BAA06C6A0B27F0CAE0F2C4074C91D38D339695512A247E0C7EA4EE5D7F78301810BDB2621A57610526B87606FCD5DD88712FB4D3FBC5D3100BB2AEEC285DE39B0564E7004646F24BBA79675A3D50B90DE300C719706E1DD2BBFC39EAB247FACACDF0EC19E2B439058330C9A150F2851ECD64D80B23CECE8F715058DF7E054E72C24D68E425CF92FB0F38B5BB0F3CBDB109D6F44400324D58F4152C304683121F14E18CA2B56F1006579B8AE79E96CD743C8304E43ECD91ED0EA9A9602767F5AE4BD3DEE90C7D61DFBA3F25AE150EB3C68F38C5605E709B844A24B4F9BFE8603F5231099D5B884676A14058A37ADE199759DAF1775581D9C2720D1A05BF3FB9621A1F427502564EAF0CC8BE24BE1417162F10E5E2B38DD0F0C0C6C0E0A0A025C4DB45F9540548E61519BDB02E46A55FC9144617211A052E15F1D18E007412A259032954A554E95C3579052A94CA2735EF8F7145EDAE3BA8556B158ECB01A01B270338A062504C59D674A4A5059255D96C964056E6E6E090A8582B308418BE93BDCEF62A0D3AEAEAEF1010101DDB4C7F364320ECF27990728B42EAB5601232141D980622B78C959804A7BF13910456E6363B38DB794BE47C553F4ECE8E8184BA17276768E61EF9799310A163E5A9D56ED034F13B4584ECAE472790923684BF9212020133C4B8930AD8233BAE3409633239FCC013349E4CE9491FBB8F86128DE1100288560EC8EE4F133B39DF019045CA452A98E5788EE1E1026DBF32040A528DBB87163BCAFAF6F254A2986A39A25DDECF320206624A8FEFD2811FDFDFDF5A4DCCBCBEB30252511A1BD8787075592183D16C508CEAF9B00095A6C87251581C0C91882595662B7C83394237C8810B0DDC7C7670BADB4974A37E956CBFA357B0081630439F0A7A7A76706EB8C4ECC3B723E2C9C60B3F2D9E4554DE7C292E63B6364B69E1BEFB438E6712DC082106C60EE0F61F52CE34B8ABD7760EF8305DFF8B173B1505FC8C1F311A9157D90D736C1CF13F696CC84B68C848401DB0A15F32D97D53A7DE3AE2D68A35F78A3B0EEA9A5871EBDD65ED63D01278DE3A059F9ADBB9825B0162190F01C235CFD790EC7360EC021E2444388FA58ED07EA2CFD78DA451334FDB6080997EED150B3CC11B62638CD8A85371F4079DF0C44E4B74154513B249CEB82F74ABAE144E320D40C2CC291D64978EBBC09423F2EAFB39A07089C668A9CB629D85D751F4A7B67E074D7347C85720EE7C712D302E476CC40FA8D49D85B3BC24D59CEDEAAD72CCA014BC0E9377EBC7D0EF6D58D7200EF7F370CA938C2A5D68FC287D72660FF8D29486B7A0829F5E3F066710704277FFE35DE7BD96C155848804A514973E3C1E6590442B0C62938A09F8674C30C7C645C80349C25E34BEF4074C10F109276E632AB123BB37DC0520FB04E194624326E2EC2E1564CC2AC26ACF5664E34D9FAE5D04F2E76BE24793586FF2DF39564B51CE04944EA0C90D5F72FD08485FB1DA295418766CCCDEC1BFBFF95B135AB80271185E0DB3FBBDCC99A9684F508FB35CF03EB20C14F40F666EF5893808084C3D32C7E5CFE037886BAD0B3E83D2A0000000049454E44AE426082")   $Form = GUICreate("", 200, 125, -1, -1) $hPic = GUICtrlCreateIcon("", "", 4, 4, 32, 32) $hDat = _IconImage_FromImageData($PngData) ConsoleWrite('-> error = ' & @Error & @CRLF) $hIcon = _IconImage_ToHandle($hDat, 32, 32) _SetHIcon($hPic, $hIcon) _WinAPI_DestroyIcon($hIcon) GUISetState(@SW_SHOW)   While 1 $nMsg = GUIGetMsg() Switch $nMsg   Case $GUI_EVENT_CLOSE    Exit EndSwitch WEnd


#4 Yashied

Yashied

    Happy in Moscow

  • MVPs
  • 2,513 posts

Posted 17 September 2011 - 09:57 PM

:graduated:

5* from me.

P.S.

Unfortunately does not support saving multiple icons in one .ico file, _WinAPI_SaveHICONToFile() supports it...

;)

Here are some functions from WinAPIEx which related to icons, and may be helpful.

_WinAPI_AddIconOverlay
_WinAPI_AddIconTransparency
_WinAPI_Create32BitHBITMAP
_WinAPI_Create32BitHICON
_WinAPI_LoadIconWithScaleDown
_WinAPI_SaveHICONToFile
_WinAPI_ShellExtractAssociatedIcon
_WinAPI_ShellExtractIcon
_WinAPI_ShellGetStockIconInfo

#5 Yashied

Yashied

    Happy in Moscow

  • MVPs
  • 2,513 posts

Posted 17 September 2011 - 10:08 PM

please tell me why the picture does not appear in the code...

_IconImage_Startup()

#6 Ward

Ward

    Adventurer

  • Active Members
  • PipPip
  • 143 posts

Posted 17 September 2011 - 10:28 PM

@Beege, thanks, I modifoed the thread.

@Yashied, thanks, too. Especially for your wonderful UDFs.

_WinAPI_AddIconOverlay use ImageList_SetOverlayImage.There is a "_IconImage_Overlay" in my UDF but I marked as "Deprecated". Because it only support icon in the same size.

_WinAPI_SaveHICONToFile is good I not noticed before. Maybe I can warp it for save multiple IconImage in my UDF.

_WinAPI_LoadIconWithScaleDown seems good for choice icon, but it only works on module. My UDF use _WinAPI_LookupIconIdFromDirectoryEx to choice icon in memory. I even convert .ico file with multiple icon to suitable for this API. How to use LoadIconWithScaleDown in memory???

#7 Ward

Ward

    Adventurer

  • Active Members
  • PipPip
  • 143 posts

Posted 17 September 2011 - 10:40 PM

@Yashied, BTW, you may add $ILD_IMAGE for ImageList_GetIcon in your _WinAPI_AddIconOverlay. On my test, this help windows 7 get the icon with alpha channel. But seems not work under XP. This also why I don't use it.

#8 Yashied

Yashied

    Happy in Moscow

  • MVPs
  • 2,513 posts

Posted 17 September 2011 - 10:43 PM

How to use LoadIconWithScaleDown in memory???

You can always get HBITMAP (DIB) from HICON.

_WinAPI_ShellExtractIcon() or _WinAPI_LoadIconWithScaleDown() => _WinAPI_Create32BitHBITMAP() => ...

If your UDF uses WinAPIEx then why not use it at maximum.

:graduated:

#9 Yashied

Yashied

    Happy in Moscow

  • MVPs
  • 2,513 posts

Posted 17 September 2011 - 10:51 PM

@Yashied, BTW, you may add $ILD_IMAGE for ImageList_GetIcon in your _WinAPI_AddIconOverlay.

No, I create an ImageList with ILC_COLOR32 flag.

Edited by Yashied, 17 September 2011 - 10:52 PM.


#10 Ward

Ward

    Adventurer

  • Active Members
  • PipPip
  • 143 posts

Posted 17 September 2011 - 10:56 PM

What I mean "use LoadIconWithScaleDown in memory" is to let it choice an single icon in "binary format .ico file with multiple icon" for display. I use LookupIconIdFromDirectoryEx to do that for now. But it just like LoadImage, sometimes "scaling up" the icon (it not really scaling up, but what it returned sometimes need scaling up to display).

If i don't want to write the "selecting subroutine" by myself, I need an API like LookupIconIdFromDirectoryEx can work on memory but won't scaling up. Although write by myself seems not hard......

#11 Ward

Ward

    Adventurer

  • Active Members
  • PipPip
  • 143 posts

Posted 17 September 2011 - 11:02 PM

No, I create an ImageList with ILC_COLOR32 flag.

Yes I know, but even you use a ILC_COLOR32 ImageList, it sometimes just not returned the icon with correct alpha channel. I try a lot of method, but only ILD_IMAGE let thing better, and only under windows 7.

Sorry, my wrong. What I mean is about ImageList_Merge, not ImageList_SetOverlayImage.....
I maybe just wake up and talk nonsense.....

Edited by Ward, 17 September 2011 - 11:13 PM.


#12 Ward

Ward

    Adventurer

  • Active Members
  • PipPip
  • 143 posts

Posted 18 September 2011 - 07:44 AM

@Yashied

I took a look of your _WinAPI_SaveHICONToFile. It is good, but it not handle alpha channel well.
The problem will occur when the hIcon is converted from non-alpha channel icon. For example, "shell32.dll,29", the link mark under winxp.
Because of lack the alpha channel data (all alpha channel is zero), this icon will be "totally transparent".
So one more thing to do is generate the alpha channel data from bitmask. Just like what I do in my _IconImage_FromHandle.

I don't know any easy way to do it. Even example on MSDN is converting it in code, not by API.
But this is a time-consuming routine. I am considering to use some machine code to do this. But not yet implement for now.

#13 Yashied

Yashied

    Happy in Moscow

  • MVPs
  • 2,513 posts

Posted 19 September 2011 - 12:46 AM

@Ward

I wrote a more productive function to create 1 bpp AND bitmask DIB from the specified 32 bpp bitmap.

AutoIt         
#Include <GDIPlus.au3> #Include <WinAPIEx.au3>   If _WinAPI_GetUDFVersion() < '3.4' Then     MsgBox(16, 'Error', 'Require WinAPIEx UDF v3.4 or later.')     Exit EndIf   $sPng = RegRead('HKLM\SOFTWARE\AutoIt v3\AutoIt', 'InstallDir') & '\Examples\GUI\Torus.png' If @error Then     Exit EndIf   Dim $Pic[2], $hBitmap[2]   _GDIPlus_Startup() $hPng = _GDIPlus_ImageLoadFromFile($sPng) $hBitmap[0] = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hPng) $Width = _GDIPlus_ImageGetWidth($hPng) $Height = _GDIPlus_ImageGetHeight($hPng) _GDIPlus_ImageDispose($hPng) _GDIPlus_Shutdown()   $hBitmap[1] = __WinAPI_CreateANDBitmap($hBitmap[0])   $hForm = GUICreate('MyGUI', $Width * 2, $Height) GUICtrlCreatePic('', 0, 0, $Width, $Height) GUICtrlSendMsg(-1, 0x0172, 0, $hBitmap[0]) GUICtrlCreatePic('', $Width, 0, $Width, $Height) GUICtrlSendMsg(-1, 0x0172, 0, $hBitmap[1]) GUISetState()   $sIcon = FileSaveDialog('Save Icon', @ScriptDir, 'Icon Files (*.ico)', 2 + 16, _WinAPI_PathStripPath(_WinAPI_PathRenameExtension($sPng, '.ico')), $hForm) If $sIcon Then     $hIcon = _WinAPI_CreateIconIndirect($hBitmap[0], $hBitmap[1])     ConsoleWrite($hIcon & @CR)     If Not @error Then         _WinAPI_SaveHICONToFile($sIcon, $hIcon)         _WinAPI_DestroyIcon($hIcon)     EndIf EndIf   Do Until GUIGetMsg() = -3   ; #FUNCTION# ==================================================================================================================== ; Name...........: _WinAPI_CreateANDBitmap ; Description....: Creates an AND bitmask device-independent bitmap (DIB) from the specified bitmap. ; Syntax.........: _WinAPI_CreateANDBitmap ( $hBitmap ) ; Parameters.....: $hBitmap - Handle to the bitmap from which to create an AND bitmask DIB. ; Return values..: Success  - Handle to the DIB. ;                 Failure  - 0 and sets the @error flag to non-zero. ; Author.........: Yashied ; Modified.......: ; Remarks........: The _WinAPI_CreateANDBitmap() creates a 1 bits-per-pixel AND bitmask DIB from the 32 bits-per-pixel DIB or DDB. ;                 If the source bitmap is not a 32 bits-per-pixel bitmap, the function fails. ; ;                 You can use the bitmap returned by this function to create icon by using the _WinAPI_CreateIconIndirect(). ; ;                 When you are finished using the bitmap, destroy it using the _WinAPI_DeleteObject() function. ; Related........: ; Link...........: None ; Example........: Yes ; ===============================================================================================================================   Func _WinAPI_CreateANDBitmap($hBitmap)       Local $Ret, $Error, $bProc, $tProc, $tBITMAP, $tDIB, $hDIB = 0, $hTemp = 0       $hBitmap = _WinAPI_CopyImage($hBitmap, 0, 0, 0, 0x2000)     If @error Then         Return SetError(1, 0, 0)     EndIf     Do         $Error = 1         $tBITMAP = DllStructCreate($tagBITMAP)         If (Not _WinAPI_GetObject($hBitmap, DllStructGetSize($tBITMAP), DllStructGetPtr($tBITMAP))) Or (DllStructGetData($tBITMAP, 'bmPlanes') <> 1) Or (DllStructGetData($tBITMAP, 'bmBitsPixel') <> 32) Then             ExitLoop         EndIf         $hTemp = _WinAPI_CreateBitmap(DllStructGetData($tBITMAP, 'bmWidth'), DllStructGetData($tBITMAP, 'bmHeight'), 1, 1)         $hDIB = _WinAPI_CopyImage($hTemp, 0, 0, 0, 0x2000)         $tDIB = DllStructCreate($tagBITMAP)         If Not _WinAPI_GetObject($hDIB, DllStructGetSize($tDIB), DllStructGetPtr($tDIB)) Then             ExitLoop         EndIf         $bProc = __ANDProc()         $tProc = DllStructCreate('byte[' & BinaryLen($bProc) & ']')         DllStructSetData($tProc, 1, $bProc)         $Ret = DllCall('user32.dll', 'int', 'CallWindowProc', 'ptr', DllStructGetPtr($tProc), 'ptr', 0, 'uint', 0, 'ptr', DllStructGetPtr($tBITMAP), 'ptr', DllStructGetPtr($tDIB))         If (@error) Or (Not $Ret[0]) Then             ExitLoop         EndIf         $Error = 0     Until 1     If $hTemp Then         _WinAPI_DeleteObject($hTemp)     EndIf     _WinAPI_DeleteObject($hBitmap)     If $Error Then         If $hDIB Then             _WinAPI_DeleteObject($hDIB)         EndIf         $hDIB = 0     EndIf     Return SetError($Error, 0, $hDIB) EndFunc   ;==>_WinAPI_CreateANDBitmap   Func __ANDProc()       Local $bData = _          '0x555357BA0900000083EC04C70424000000004A75F3837C243C00740431C0EB05' & _            'B80100000021C07562837C244000740431C0EB05B80100000021C0753F8B6C24' & _            '3C837D1400740431C0EB05B80100000021C075198B6C2440837D1400740431C0' & _            'EB05B80100000021C07502EB07B801000000EB0231C021C07502EB07B8010000' & _            '00EB0231C021C07502EB07B801000000EB0231C021C0740731C0E9BA0100008B' & _            '6C24408B5D0489D8BB0800000099F7FB89D3891C24833C240074268B6C24408B' & _            '5D0C8B6C24408B7D042B3C2489F8B90800000099F7F989C729FB4B895C2404EB' & _            '208B6C24408B5D0C8B6C24408B7D0489F8B90800000099F7F989C729FB895C24' & _            '04C744240800000000C744240C00000000C744241000000000C7442414000000' & _            '00C7442418000000008B6C243C8B5D048B6C243C0FAF5D08C1E3024B3B5C2418' & _            '0F8C0A0100008B6C243C8B5D14035C241883C303895C241C8B6C241C807D0000' & _            '741C8B5C24148B7C240CF7DF83C70789F9B801000000D3E009C3895C2414FF44' & _            '240C8B5C240C83FB077E328B6C24408B5D14035C2408895C241C8B5C2414F7D3' & _            '538B6C242058884500FF442408C744240C00000000C744241400000000FF4424' & _            '108B5C24108B6C24408B7D044F39FB7E74837C240C0074328B6C24408B5D1403' & _            '5C2408895C241C8B5C2414F7D3538B6C242058884500FF442408C744240C0000' & _            '0000C744241400000000C7442420010000008B4424043B4424207C218B6C2440' & _            '8B5D14035C2408895C241C8B6C241CC64500FFFF442408FF44242071D5C74424' & _            '100000000083442418040F81D9FEFFFFB801000000EB0231C083C4245F5B5DC2' & _            '1000'       Return Binary($bData) EndFunc   ;==>__ANDProc

Edited by Yashied, 19 September 2011 - 12:53 AM.


#14 Ward

Ward

    Adventurer

  • Active Members
  • PipPip
  • 143 posts

Posted 19 September 2011 - 02:06 AM

@Yashied

Haha, I just did the similar thing, only for icon but also with x64 support. :graduated:
This is my new _IconImage_FromHandle function.
Much much fast than old version after use machine code.

AutoIt         
; Modified from Yashied's code Func _IconImage_FromHandle($Handle, $CustomColorBmp = 0) If Not $Handle Then Return SetError(1, 0, Binary("")) Local $Info = _WinAPI_GetIconInfo($Handle) If @Error Then Return SetError(1, 0, Binary("")) Local $Height, $Width, $ColorSizeImage, $MaskSizeImage, $ColorBuffer, $MaskBuffer Local $MaskBmp = $Info[4] Local $ColorBmp = $Info[5] If $CustomColorBmp Then $ColorBmp = $CustomColorBmp $MaskBmp = _WinAPI_CopyImage($MaskBmp, 0, 0, 0, 0x2008) $ColorBmp = _WinAPI_CopyImage($ColorBmp, 0, 0, 0, 0x2008) Local $DIBSection = DllStructCreate($tagDIBSECTION) Local $Ptr = DllStructGetPtr($DIBSection) Local $Size = DllStructGetSize($DIBSection) _WinAPI_GetObject($MaskBmp, $Size, $Ptr) Local $MaskBitsPtr = DllStructGetData($DIBSection, 'bmBits') Local $MaskSizeImage = DllStructGetData($DIBSection, 'biSizeImage') _WinAPI_GetObject($ColorBmp, $Size, $Ptr) Local $ColorBitsPtr = DllStructGetData($DIBSection, 'bmBits') Local $ColorSizeImage = DllStructGetData($DIBSection, 'biSizeImage') Local $Width = DllStructGetData($DIBSection, 'bmWidth') Local $Height = DllStructGetData($DIBSection, 'bmHeight') If DllStructGetData($DIBSection, 'biBitCount') <> 32 Then   Local $Error = 0, $Ret = Binary("")   Local $Icon32Bit = _WinAPI_Create32BitHICON($Handle)   If Not @Error Then    $Ret = _IconImage_FromHandle($Icon32Bit, $CustomColorBmp)    $Error = @Error   EndIf   _WinAPI_DestroyIcon($Icon32Bit)   Return SetError($Error, 0, $Ret) EndIf Static $AlphaCreatePtr If Not $AlphaCreatePtr Then   Local $Code   If @AutoItX64 Then    $Code = "0x4883EC084989C931C0EB0F41F701000000FF754D4983C104FFC04439C072EC4883C10431C0EB354189C141C1E9034589C9460FBE140A4189C141F7D14183E107450FA3CA7309C741FC00000000EB078149FC000000FFFFC04883C1044439C072C658C3"   Else    $Code = "0x5531C089E5578B5508568B750C538B5D10EB0AF70482000000FF75394039D872F283C20431C0EB2989C1C1E9030FBE3C0E89C1F7D183E1070FA3CF7309C742FC00000000EB07814AFC000000FF4083C20439D872D35B5E5F5DC21000"   EndIf   $AlphaCreatePtr = __BinaryCodeBufferAlloc(Binary($Code)) EndIf DllCall("user32.dll", "none", "CallWindowProc", "ptr", $AlphaCreatePtr, _              "ptr", $ColorBitsPtr, _              "ptr", $MaskBitsPtr, _              "uint", $Width * $Height, _              "int", 0) Local $Header = DllStructCreate(StringReplace($tagBITMAPINFO, "dword RGBQuad", "")) DllStructSetData($Header, "Size", 40) DllStructSetData($Header, "Planes", 1) DllStructSetData($Header, "BitCount", 32) ;DllStructSetData($Header, "Compression", 0) ;DllStructSetData($Header, "XPelsPerMeter", 0) ;DllStructSetData($Header, "YPelsPerMeter", 0) ;DllStructSetData($Header, "ClrUsed", 0) ;DllStructSetData($Header, "ClrImportant", 0) ;DllStructSetData($Header, "Compression", 0) DllStructSetData($Header, "Width", $Width) DllStructSetData($Header, "Height", $Height * 2) DllStructSetData($Header, "SizeImage", $ColorSizeImage + $MaskSizeImage) Local $IconImage = _BinaryFromDLLStruct($Header) & _BinaryFromMemory($ColorBitsPtr, $ColorSizeImage) & _BinaryFromMemory($MaskBitsPtr, $MaskSizeImage) _WinAPI_DeleteObject($MaskBmp) _WinAPI_DeleteObject($ColorBmp) Return SetError(0, 0, $IconImage) EndFunc


#15 Yashied

Yashied

    Happy in Moscow

  • MVPs
  • 2,513 posts

Posted 19 September 2011 - 11:26 AM

But why do it for HICON? This responsibility should rest with the user. All HICON that returns API functions already contain a bitmask. Anyway, I found a bug(?) in new _IconImage_FromHandle(). How you generate a bitmask? Byte comparison?

#Include "IconImage.au3" _IconImage_Startup() $hIcon = _WinAPI_ShellExtractIcon(@SystemDir & '\shell32.dll', 3, 40, 48) $bIcon = _IconImage_FromHandle($hIcon) $hIcon = _IconImage_ToHandle($bIcon) _IconImage_Shutdown() $hForm = GUICreate('', 400, 400) GUISetState() $aIcon = _WinAPI_GetIconInfo($hIcon) $hDC = _WinAPI_GetDC($hForm) _WinAPI_DrawIconEx($hDC, 30, 30, $hIcon) _WinAPI_DrawBitmap($hDC, 90, 30, $aIcon[4]) _WinAPI_ReleaseDC($hForm, $hDC) Do Until GUIGetMsg() = -3


#16 Ward

Ward

    Adventurer

  • Active Members
  • PipPip
  • 143 posts

Posted 19 September 2011 - 01:01 PM

@Yashied

You are right. I know what's my problem.
The _WinAPI_GetIconInfo always return 32bit bitmap even the icon is not 32bit.
So _WinAPI_SaveHICONToFile is always works even on non-32bit icon. For example:
$hIcon = _WinAPI_ShellExtractIcon(@SystemDir & '\shell32.dll', 29, 48, 48) _WinAPI_SaveHICONToFile("test.ico", $hIcon)

But in this case, the 32bit bitmap has no alpha channel, so the result of the icon is totally transparent.
What I want to do is adding the alpha channel by myself (convert from bitmask).

You said "use the _WinAPI_Create32BitHICON" is the more convenient way. I miss it before.
This hIcon returned by _WinAPI_Create32BitHICON always has correct alpha channel.

My new _IconImage_FromHandle may be need change for generating the correct result.
But it seems always calling _WinAPI_Create32BitHICON before _IconImage_FromHandle is a better way.

However, is there a way to know is the hIcon need _WinAPI_Create32BitHICON or not?

Edited by Ward, 19 September 2011 - 01:05 PM.


#17 Ward

Ward

    Adventurer

  • Active Members
  • PipPip
  • 143 posts

Posted 19 September 2011 - 02:23 PM

There is still some problem if I always use _WinAPI_Create32BitHICON.
For example, this PNG file. When use following code:
_IconImage_Startup() $Icon = _IconImage_FromImageFile("KevinMoore_happy.png") $hIcon = _IconImage_ToHandle($Icon) $hIcon = _WinAPI_Create32BitHICON($hIcon, 1) _WinAPI_SaveHICONToFile("test.ico", $hIcon)

The result is bad. Because the returned $Icon already have alpha channel.
But if don't use _WinAPI_Create32BitHICON in this example, everything is ok.

So, it is still import to know when to use _WinAPI_Create32BitHICON.
My suggestion is to use the similar code I did before to decide $HasAlpha. And convert it to machine code for speed.

--
I found someone had already discussed this before. This link.
The conclusion: "There is no other way except scanning for alpha channel."

Edited by Ward, 19 September 2011 - 02:52 PM.


#18 Yashied

Yashied

    Happy in Moscow

  • MVPs
  • 2,513 posts

Posted 19 September 2011 - 03:24 PM

@Ward

_WinAPI_SaveHICONToFile() saves an icon as is, without any changes. However, for correct icons conversion, I always use _WinAPI_Create32BitHICON() through the ImageList. This ensures that the output icon is 32 bpp + bitmask (if exists) with which you can work without any violence of the brain. Independent creation bitmask is only necessary if the icon is created from an image (PNG) and then save it to a file. Furthermore, Windows uses this bitmask only if the output device does not support 32 bpp color depth. If you do not plan to save HICON into a file, the bitmask does not needed (unless Windows is running in 32 bpp mode).

There is still some problem if I always use _WinAPI_Create32BitHICON.

This problem is not in _WinAPI_Create32BitHICON() or _WinAPI_SaveHICONToFile () function. For example:

AutoIt         
#Include <GDIPlus.au3> #Include <WinAPIEx.au3>   ;_IconImage_Startup() ;$Icon = _IconImage_FromImageFile("KevinMoore_happy.png") ;$hIcon = _IconImage_ToHandle($Icon)   ; Just create 32 bpp bitmap _GDIPlus_Startup() $hPng = _GDIPlus_ImageLoadFromFile("KevinMoore_happy.png") $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hPng) _GDIPlus_ImageDispose($hPng) _GDIPlus_Shutdown()   ; Test 1 - bitmap + bitmask $hMask = _WinAPI_CreateANDBitmap($hBitmap) $hIcon = _WinAPI_CreateIconIndirect($hBitmap, $hMask) _WinAPI_SaveHICONToFile("test1.ico", $hIcon)   ; Test 2 - bitmap + bitmask + _WinAPI_Create32BitHICON() $hIcon = _WinAPI_Create32BitHICON($hIcon, 1) _WinAPI_SaveHICONToFile("test2.ico", $hIcon) _WinAPI_DeleteObject($hMask) _WinAPI_DestroyIcon($hIcon)   ; Test 3 - bitmap + null bitmask $hMask = _WinAPI_CreateBitmap(145, 175, 1, 1) $hIcon = _WinAPI_CreateIconIndirect($hBitmap, $hMask) _WinAPI_SaveHICONToFile("test3.ico", $hIcon)   ; Test 4 - bitmap + null bitmask + _WinAPI_Create32BitHICON() $hIcon = _WinAPI_Create32BitHICON($hIcon, 1) _WinAPI_SaveHICONToFile("test4.ico", $hIcon) _WinAPI_DeleteObject($hBitmap) _WinAPI_DeleteObject($hMask) _WinAPI_DestroyIcon($hIcon)

All four icons will look good and exactly the same as the original PNG. I think the problem is in GdipCreateHICONFromBitmap() function. Another demonstration:

AutoIt         
#Include <GDIPlus.au3> #Include <IconImage.au3> #Include <WinAPIEx.au3>   $hDC = _WinAPI_GetDC(0)   ; Your example _IconImage_Startup() $Icon = _IconImage_FromImageFile("KevinMoore_happy.png") $hIcon = _IconImage_ToHandle($Icon)   $aIcon = _WinAPI_GetIconInfo($hIcon) _WinAPI_DrawBitmap($hDC, 0, 0, $aIcon[5]) _WinAPI_DrawBitmap($hDC, 145, 0, $aIcon[4])   $hIcon = _WinAPI_Create32BitHICON($hIcon, 1)   $aIcon = _WinAPI_GetIconInfo($hIcon) _WinAPI_DrawBitmap($hDC, 0, 175, $aIcon[5]) _WinAPI_DrawBitmap($hDC, 145, 175, $aIcon[4])   ; My example _GDIPlus_Startup() $hPng = _GDIPlus_ImageLoadFromFile("KevinMoore_happy.png") $hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hPng) _GDIPlus_ImageDispose($hPng) _GDIPlus_Shutdown() $hMask = __WinAPI_CreateANDBitmap($hBitmap) $hIcon = _WinAPI_CreateIconIndirect($hBitmap, $hMask)   $aIcon = _WinAPI_GetIconInfo($hIcon) _WinAPI_DrawBitmap($hDC, 0, 350, $aIcon[5]) _WinAPI_DrawBitmap($hDC, 145, 350, $aIcon[4])   $hIcon = _WinAPI_Create32BitHICON($hIcon, 1)   $aIcon = _WinAPI_GetIconInfo($hIcon) _WinAPI_DrawBitmap($hDC, 0, 525, $aIcon[5]) _WinAPI_DrawBitmap($hDC, 145, 525, $aIcon[4])

Posted Image

Note that your first icon is different from the others (white background).

Edited by Yashied, 19 September 2011 - 03:50 PM.


#19 Yashied

Yashied

    Happy in Moscow

  • MVPs
  • 2,513 posts

Posted 19 September 2011 - 04:31 PM

Yes, I was right, GdipCreateHICONFromBitmap() creates an icon without alpha channel and broken bitmask.

#Include <GDIPlus.au3> #Include <WinAPIEx.au3> _GDIPlus_Startup() $hPng = _GDIPlus_ImageLoadFromFile('KevinMoore_happy.png') $hIcon = DllCall($ghGDIPDll, 'uint', 'GdipCreateHICONFromBitmap', 'ptr', $hPng, 'ptr*', 0) _GDIPlus_ImageDispose($hPng) _GDIPlus_Shutdown() $hDC = _WinAPI_GetDC(0) $aInfo = _WinAPI_GetIconInfo($hIcon[2]) _WinAPI_DrawIconEx($hDC, 0, 0, $hIcon[2]) _WinAPI_DrawBitmap($hDC, 145, 0, $aInfo[5]) _WinAPI_DrawBitmap($hDC, 290, 0, $aInfo[4]) _WinAPI_DeleteObject($aInfo[4]) _WinAPI_DeleteObject($aInfo[5]) _WinAPI_DestroyIcon($hIcon[2]) _WinAPI_ReleaseDC(0, $hDC)

Posted Image

#20 Ward

Ward

    Adventurer

  • Active Members
  • PipPip
  • 143 posts

Posted 19 September 2011 - 09:28 PM

@Yashied

Ok, you are right. The problem is at GdipCreateHICONFromBitmap.
I change my code as following and don't use GdipCreateHICONFromBitmap, than it seems everything is ok?
(But this convert ColorBmp and MaskBmp into hicon, than get it again by _WinAPI_GetIconInfo, look stupid. So just for test, still need modify...)

Spoiler

Edited by Ward, 19 September 2011 - 09:31 PM.





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users