Jump to content

IconImage UDF


Ward
 Share

Recommended Posts

Func _IconImage_FromGdipBitmap($Gdibmp)
 
    Local $tDIBSECTION, $aSize, $tData, $tHeader, $Error, $pBits, $hBitmap, $hMask = 0
    Local $BitmapSize, $BitmapBits, $MaskSize, $MaskBits
    Local $IconImage = Binary("")
 
    $aSize = DllCall($ghGDIPDll, "uint", "GdipGetImageDimension", "ptr", $Gdibmp, "float*", 0, "float*", 0)
    If (@error) Or ($aSize[0]) Then
        Return SetError(1, 0, $IconImage)
    EndIf
    $tData = _GDIPlus_BitmapLockBits($Gdibmp, 0, 0, $aSize[2], $aSize[3], $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    $pBits = DllStructGetData($tData, "Scan0")
    If Not $pBits Then
        Return SetError(1, 0, $IconImage)
    EndIf
    $hBitmap = _WinAPI_CreateDIB($aSize[2], $aSize[3])
    If Not @error Then
        _WinAPI_SetBitmapBits($hBitmap, $aSize[2] * $aSize[3] * 4, $pBits)
    EndIf
    _GDIPlus_BitmapUnlockBits($Gdibmp, $tData)
    If Not $hBitmap Then
        Return SetError(1, 0, $IconImage)
    EndIf
    Do
        $Error = 1
        $tDIBSECTION = DllStructCreate($tagDIBSECTION)
        If Not _WinAPI_GetObject($hBitmap, DllStructGetSize($tDIBSECTION), DllStructGetPtr($tDIBSECTION)) Then
            ExitLoop
        EndIf
        $BitmapSize = DllStructGetData($tDIBSECTION, "biSizeImage")
        $BitmapBits = DllStructGetData($tDIBSECTION, "bmBits")
        $hMask = _WinAPI_CreateANDBitmap($hBitmap)
        If @error Then
            ExitLoop
        EndIf
        If Not _WinAPI_GetObject($hMask, DllStructGetSize($tDIBSECTION), DllStructGetPtr($tDIBSECTION)) Then
            ExitLoop
        EndIf
        $MaskSize = DllStructGetData($tDIBSECTION, "biSizeImage")
        $MaskBits = DllStructGetData($tDIBSECTION, "bmBits")
        $Error = 0
    Until 1
    If Not $Error Then
        $tHeader = DllStructCreate(StringReplace($tagBITMAPINFO, "dword RGBQuad", ""))
        DllStructSetData($tHeader, "Size", 40)
        DllStructSetData($tHeader, "Planes", 1)
        DllStructSetData($tHeader, "BitCount", 32)
        DllStructSetData($tHeader, "Width", $aSize[2])
        DllStructSetData($tHeader, "Height", $aSize[3] * 2)
        DllStructSetData($tHeader, "SizeImage", $BitmapSize + $MaskSize)
        $IconImage = _BinaryFromDLLStruct($tHeader) & _BinaryFromMemory($BitmapBits, $BitmapSize) & _BinaryFromMemory($MaskBits, $MaskSize)
    EndIf
    _WinAPI_DeleteObject($hBitmap)
    If $hMask Then
        _WinAPI_DeleteObject($hMask)
    EndIf
    Return SetError($Error, 0, $IconImage)
EndFunc   ;==>_IconImage_FromGdipBitmap

I'll include _WinAPI_CreateANDBitmap() in WinAPIEx UDF in the next release.

:graduated:

Edited by Yashied
Link to comment
Share on other sites

I'll include _WinAPI_CreateANDBitmap() in WinAPIEx UDF in the next release.

:graduated:

Thanks, Yashied.

I am waiting, and then I will update IconImage to use your _WinAPI_CreateANDBitmap ;).

But you use DllStructCreate to allocate the buffer for machine code, don't forget use VirtualProtect to set the memory block to PAGE_EXECUTE_READWRITE. Or just use _MemVirtualAlloc(0, BinaryLen($Code), $MEM_COMMIT, $PAGE_EXECUTE_READWRITE). This will avoid the DEP issue.

Edited by Ward

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

 

Link to comment
Share on other sites

But you use DllStructCreate to allocate the buffer for machine code, don't forget use VirtualProtect to set the memory block to PAGE_EXECUTE_READWRITE. Or just use _MemVirtualAlloc(0, BinaryLen($Code), $MEM_COMMIT, $PAGE_EXECUTE_READWRITE). This will avoid the DEP issue.

I know about it, and rewrote _WinAPI_CreateANDBitmap() (32- and 64-bit) for the final release.

Thanks for your wonderful UDF and another contribution to the AutoIt!

P.S

Also I will include _WinAPI_ReleaseStream() by Prog@ndy.

Edited by Yashied
Link to comment
Share on other sites

After some test, I found that even windows 7 don't handle PNG icon well.

For example, try following code:

$hIcon = _WinAPI_ShellExtractIcon("imageres.dll", 3, 256, 256)
$hIcon = _WinAPI_Create32BitHICON($hIcon, 1)
_WinAPI_SaveHICONToFile("test1.ico", $hIcon)
 
$Icon = _IconImage_FromPEEX("imageres.dll,3", 256, 256)
$hIcon = _IconImage_ToHandle($Icon)
$hIcon = _WinAPI_Create32BitHICON($hIcon, 1)
_WinAPI_SaveHICONToFile("test2.ico", $hIcon)
 
$Icon = _IconImage_FromPEEX("imageres.dll,3", 256, 256)
$Icon = _IconImage_ConvertToBMPIcon($Icon)
_IconImage_ToIcoFile($Icon, "test3.ico")
 
$Icon = _IconImage_FromPEEX("imageres.dll,3", 256, 256)
$Icon = _IconImage_ConvertToBMPIcon($Icon)
$hIcon = _IconImage_ToHandle($Icon)
$hIcon = _WinAPI_Create32BitHICON($hIcon, 1)
_WinAPI_SaveHICONToFile("test4.ico", $hIcon)

Are all the 4 icon the same? No, only test3 and test4 is good, look like

Posted Image

But 1 and 2 look like:

Posted Image

I think it is because that test1 use _WinAPI_ShellExtractIcon, it convert PNG icon by system.

test2 use _IconImage_ToHandle, it will call _WinAPI_CreateIconFromResourceEx (convert by system, too).

test3 and test4 are using _IconImage_ConvertToBMPIcon, it convert the PNG icon by GDI+.

For now, I use the $_IconImage_VistaFlag to decide how to convert the PNG icon (by system or by GDI+).

But it seems always using GDI+ is necessary for good result.

Edited by Ward

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

 

Link to comment
Share on other sites

Haha, the problem in the ImageList that is used in _WinAPI_Create32BitHICON(). Apparently, ImageList does not works correctly with icons that use a PNG compression. If icon does not use a PNG compression, everything works fine. I'll think about it.

Link to comment
Share on other sites

@Yashied

I think not only _WinAPI_Create32BitHICON, even _WinAPI_ShellExtractIcon has problem. For example:

_IconImage_Startup()
 
$GUI = GUICreate("", 520, 520)
GUISetState()
 
$Icon = _IconImage_FromPEEX("imageres.dll,3", 256, 256)
$Icon = _IconImage_ConvertToBMPIcon($Icon)
$hIcon1 = _IconImage_ToHandle($Icon)
$hIcon2 = _WinAPI_ShellExtractIcon("imageres.dll", 3, 256, 256)
 
$aInfo1 = _WinAPI_GetIconInfo($hIcon1)
$aInfo2 = _WinAPI_GetIconInfo($hIcon2)
 
$hDC = _WinAPI_GetDC($GUI)
_WinAPI_DrawAlphaBitmap($hDC, 0, 0, $aInfo1[5])
_WinAPI_DrawBitmap($hDC, 256, 0, $aInfo1[4])
 
_WinAPI_DrawAlphaBitmap($hDC, 0, 256, $aInfo2[5])
_WinAPI_DrawBitmap($hDC, 256, 256, $aInfo2[4])
 
Do
Sleep(10)
Until GUIGetMsg() = -3
 
Exit
 
Func _WinAPI_DrawAlphaBitmap($hDC, $iX, $iY, $hBitmap, $iRop = 0x00CC0020)
Local $Ret, $tObj, $_hDC, $hSrcDC, $hSrcSv
 
    $tObj = DllStructCreate($tagBITMAP)
$Ret = DllCall('gdi32.dll', 'int', 'GetObject', 'int', $hBitmap, 'int', DllStructGetSize($tObj), 'ptr', DllStructGetPtr($tObj))
If (@error) Or (Not $Ret[0]) Then
Return SetError(1, 0, 0)
EndIf
$Ret = DllCall('user32.dll', 'hwnd', 'GetDC', 'hwnd', 0)
$_hDC = $Ret[0]
$Ret = DllCall('gdi32.dll', 'hwnd', 'CreateCompatibleDC', 'hwnd', $_hDC)
$hSrcDC = $Ret[0]
$Ret = DllCall('gdi32.dll', 'hwnd', 'SelectObject', 'hwnd', $hSrcDC, 'ptr', $hBitmap)
$hSrcSv = $Ret[0]
Local $Width = DllStructGetData($tObj, 'bmWidth')
Local $Height = DllStructGetData($tObj, 'bmHeight')
_WinAPI_AlphaBlend($hDC, $iX, $iY, $Width, $Height, $hSrcDC, 0, 0, $Width, $Height, 255, 1)
DllCall('user32.dll', 'int', 'ReleaseDC', 'hwnd', 0, 'hwnd', $_hDC)
DllCall('gdi32.dll', 'ptr', 'SelectObject', 'hwnd', $hSrcDC, 'ptr', $hSrcSv)
DllCall('gdi32.dll', 'int', 'DeleteDC', 'hwnd', $hSrcDC)
If Not IsArray($Ret) Then
Return SetError(1, 0, 0)
EndIf
Return 1
EndFunc

The result:

Posted Image

Compare to the real PNG file store in imageres.dll,3 (just extracted and save as .png file):

Posted Image

You can see _WinAPI_ShellExtractIcon convert the PNG with some error.

If the problem is in the _WinAPI_Create32BitHICON, my test4.ico should has problem, but it not.

I think if the PNG is converted to hIcon in the correct way, then _WinAPI_Create32BitHICON will work without problem.

So maybe the main problem is due to Microsoft, not in yours, or my code.

--

After some more test, I thank both _WinAPI_ShellExtractIcon and _WinAPI_Create32BitHICON have problem...

I will write some code to decide when to use _WinAPI_Create32BitHICON.

Edited by Ward

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

 

Link to comment
Share on other sites

@Yashied

I updated the UDF.

It use my own version of _WinAPI_CreateANDBitmap and also some binary code to decide is there any alpha channel bits in colorbmp of hicon.

If there is no alpha channel, than it create the colorbmp again by your _WinAPI_Create32BitHBITMAP to get a correct alpha channel.

It also not let _WinAPI_CreateIconFromResourceEx to convert the PNG image. The conversion is always done by GDI+.

I am still waiting for your new version of WinAPIEx :graduated:

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

 

Link to comment
Share on other sites

I found a bug.

DllCall($__Binary_User32Dll, "none", "CallWindowProc", "ptr", $CodePtr, "ptr", $BitPtr, "ptr", $MaskPtr, "uint", $Width, "uint", $Height)

The fourth parameter must be of UINT (4 bytes) type but you pass a PTR (4/8 bytes).

Edited by Yashied
Link to comment
Share on other sites

Thanks, Yashied. Although under my test, memory pointer return by _MemVirtualAlloc always < 0xFFFFFFFF under Windows 7.

But you are right, this is still dangerous. I will change the parameter sequence.

However, I think DllCallAddress is better solution.

Thank to the developer of AutoIt, we will have DllCallAddress in next standard release.

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

 

Link to comment
Share on other sites

I completely rewrote the _WinAPI_Create32BitHICON function. Now it guaranteed creates a 32 bits-per-pixel icon containing an alpha channel and AND bitmask bitmap. Here its description.

The _WinAPI_Create32BitHICON() converts an icon with any color depth into an icon with 32 bits-per-pixel (RGB + Alpha) format. If the source icon already is a 32 bits-per-pixel icon, and has an alpha chanel, the function generates the new AND bitmask bitmap, and copies it to a new icon. If the source icon has a 32 bits-per-pixel color depth, and do not have an alpha chanel, the function creates an alpha chanel from its AND bitmask. If the source icon is non 32 bits-per-pixel icon, it will be converted into a 32 bits-per-pixel format with alpha chanel. The _WinAPI_Create32BitHICON() always creates an icon with alpha channel and AND bitmask, although it is not used to display icons that contain an alpha channel.

The final release of WinAPIEx UDF I'll post in the next few days. Edited by Yashied
Link to comment
Share on other sites

  • 2 weeks later...
  • 1 year later...

Hi,

i would be very interessted in using your UDF but

i got lots of

ERROR: $SYNCHRONIZE previously declared as a 'Const'.

caused by the "APIConstants.au3" which is needed by WinApiEx

I am relativly new to AutoIt but even dont understand this error after long google journey

regards

Bluesmaster

My UDF: [topic='156155']_shellExecuteHidden[/topic]

Link to comment
Share on other sites

  • 1 year later...

I'm trying to use this UDF, but it crashes with a strange error:

!>13:11:31 AutoIt3.exe ended.rc:-1073741819

I'd like to save a .ICO file starting from a .PNG image, is this code the solution? thanks!

SFTPEx, AutoCompleteInput_DateTimeStandard(), _ImageWriteResize()_GUIGraduallyHide(): some AutoIt functions.

Lupo PenSuite: all-in-one and completely free selection of portable programs and games.

DropIt: a personal assistant to automatically manage your files.

ArcThemALL!: application to multi-archive your files and folders.

Link to comment
Share on other sites

I already use it  :ermm:

I'm doing some tests.. the problem seems in these lines:

Local $Header = DllStructCreate($tagBITMAPINFO)
ConsoleWrite('1 ' & @Error & @CRLF) ; <<<<<<<<<<<<<<<<< @Error = 0
ConsoleWrite('2 ' & $Header & @CRLF) ; <<<<<<<<<<<<<<<<< $Header = ''
ConsoleWrite('3 ' & $tagBITMAPINFO & @CRLF) ; <<<<<<<<<<<<<<<<< $tagBITMAPINFO = struct;dword biSize;long biWidth;long biHeight;word biPlanes;word biBitCount;dword biCompression;dword biSizeImage;long biXPelsPerMeter;long biYPelsPerMeter;dword biClrUsed;dword biClrImportant;endstruct;dword biRGBQuad[1]
DllStructSetData($Header, "Size", 40)
DllStructSetData($Header, "Width", $Width)
DllStructSetData($Header, "Height", $Height)
DllStructSetData($Header, "Planes", 1)
DllStructSetData($Header, "BitCount", 1)
DllStructSetData($Header, "SizeImage", $Stride * $Height)
ConsoleWrite('4 ' & @Error & @CRLF) ; <<<<<<<<<<<<<<<<< @Error = 2

All the DllStructSetData return 2 as error and after the second Do-Until loop the script crashes.

SFTPEx, AutoCompleteInput_DateTimeStandard(), _ImageWriteResize()_GUIGraduallyHide(): some AutoIt functions.

Lupo PenSuite: all-in-one and completely free selection of portable programs and games.

DropIt: a personal assistant to automatically manage your files.

ArcThemALL!: application to multi-archive your files and folders.

Link to comment
Share on other sites

I uploaded the last version for AutoIt v3.3.10.2 after I had seen your post.

So I don't believe "YOU ALREADY USE IT"....

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

 

Link to comment
Share on other sites

Sorry, I misunderstood, I read "the last version of AutoIt" instead of "the last version for AutoIt"  :>

It perfectly works now, thanks!

SFTPEx, AutoCompleteInput_DateTimeStandard(), _ImageWriteResize()_GUIGraduallyHide(): some AutoIt functions.

Lupo PenSuite: all-in-one and completely free selection of portable programs and games.

DropIt: a personal assistant to automatically manage your files.

ArcThemALL!: application to multi-archive your files and folders.

Link to comment
Share on other sites

  • 2 years later...

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