Ward

IconImage UDF

41 posts in this topic

#1 ·  Posted (edited)

"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

 


Startup and shutdown.
_IconImage_Startup()
_IconImage_Shutdown()

Loading associated icon for files or icon in PE files. (The width and height here are only "suggestion". Real size of returned icon should get by _IconImage_GetSize).

_IconImage_FromPath($Path, $Width, $Height = Default)
_IconImage_FromPE($IconPE, $Index, $Width, $Height = Default)
_IconImage_FromPEEx($IconFile, $Width, $Height = Default)

Conversion between windows icon handle (hIcon). The width and height here are what you really desired for display.

_IconImage_FromHandle($Handle)
_IconImage_ToHandle($IconImage, $Width = Default, $Height = Default)

Other icon format conversions. From or To "Data" means binary format in AutoIt.
From/To GdipBitmap is not only GdipCreateHICONFromBitmap or GdipCreateBitmapFromHICON. These functions handle icon with alpha channel well.

_IconImage_FromIcoData($IconData, $Width, $Height = Default)
_IconImage_FromIcoFile($IconFile, $Width, $Height = Default)
_IconImage_FromImageData($ImageData)
_IconImage_FromImageFile($Filename)
_IconImage_FromGdipBitmap($Gdibmp)
_IconImage_ToIcoData($IconImage)
_IconImage_ToIcoFile($IconImage, $Filename)
_IconImage_ToImageData($IconImage, $Type = "PNG")
_IconImage_ToImageFile($IconImage, $Filename, $Type = "PNG")
_IconImage_ToGdipBitmap($IconImage)

Special functions to handle Vista PNG format icon. Function "ConvertToBMPIcon" make windows XP support Vista icon.

_IconImage_IsPNGIcon($IconImage)
_IconImage_ConvertToBMPIcon($IconImage)
_IconImage_ConvertToPNGIcon($IconImage)

Other useful icon management. The $Flag for RotateFlip and $Align for Merge are defined as $ICONIMAGE_ALIGN_XXX and $GDIP_RotateXXXFlipXXX.

_IconImage_GetSize($IconImage)
_IconImage_Scale($IconImage, $Width, $Height = Default, $Quality = Default)
_IconImage_RotateFlip($IconImage, $Flag)
_IconImage_Merge($IconImage1, $IconImage2, $Align = 0, $X = 0, $Y = 0)

 



Screenshots of Example

 


IconImageExample1.png

IconImageExample2.png



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.

IconImage.zip

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.

IconImage.zip

2014/03/19 Update Note:

  • Update for AutoIt v3.3.10.2

IconImage.zip

Edited by Ward
1 person likes this

新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Share this post


Link to post
Share on other sites



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:

Share this post


Link to post
Share on other sites

Ward,

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

#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

Share this post


Link to post
Share on other sites

: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

Share this post


Link to post
Share on other sites

@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???


新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Share this post


Link to post
Share on other sites

@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.


新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Share this post


Link to post
Share on other sites

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:

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

Share this post


Link to post
Share on other sites

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......


新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

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

新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Share this post


Link to post
Share on other sites

@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.


新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

@Ward

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

#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

Share this post


Link to post
Share on other sites

@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.

; 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

新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

#16 ·  Posted (edited)

@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

新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Share this post


Link to post
Share on other sites

#17 ·  Posted (edited)

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

新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Share this post


Link to post
Share on other sites

#18 ·  Posted (edited)

@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:

#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:

#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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

#20 ·  Posted (edited)

@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...)

Func _IconImage_FromGdipBitmap($Gdibmp)
Local $Error = 1, $IconImage = Binary("")
Local $Width = _GDIPlus_ImageGetWidth($Gdibmp)
Local $Height = _GDIPlus_ImageGetHeight($Gdibmp)
Local $ColorBmp = _GDIPlus_BitmapCreateHBITMAPFromBitmap($Gdibmp)
If Not @Error Then
  Local $MaskBmp = _WinAPI_CreateANDBitmap($ColorBmp)
  If Not @Error Then
   Local $hIcon = _WinAPI_CreateIconIndirect($ColorBmp, $MaskBmp, Int($Width / 2), Int($Height / 2), 1)
   If Not @Error Then
    $IconImage = _IconImage_FromHandle($hIcon)
    $Error = @Error
    _WinAPI_DestroyIcon($hIcon)
   EndIf
   _WinAPI_DeleteObject($MaskBmp)
  EndIf
  _WinAPI_DeleteObject($ColorBmp)
EndIf
Return SetError($Error, 0, $IconImage)
EndFunc
 
 
; Modified from Yashied's code
Func _IconImage_FromHandle($Handle)
If Not $Handle Then Return SetError(1, 0, Binary(""))
 
$Handle = _WinAPI_Create32BitHICON($Handle, 1)
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]
 
$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')
 
Local $Header = DllStructCreate(StringReplace($tagBITMAPINFO, "dword RGBQuad", ""))
DllStructSetData($Header, "Size", 40)
DllStructSetData($Header, "Planes", 1)
DllStructSetData($Header, "BitCount", 32)
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

Edited by Ward

新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Share this post


Link to post
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