I've been trying for days to figure out a way of extracting the large 255x255 resolution Icons found in a vista resource file, and saving it to a PNG but havent been quite successful.
I originally used the Gdi_BitmapfromHicon function after extracting and getting handle to the icon, and then saving the bitmap, but it looses any alpha chanel info. the image might have, leaving it with a very nasty-looking black outline around it.
I looked on the MSDN and other sites for alternatives, and came across an article that explained that the DrawIconex function could be used to draw the mask of the icon to one DC, the actual Image to another, and use BitBlt to combine both, using 2 different raster methods 3 times in a row... (or at least thats what I understood, Im probably wrong, which is why I'm here I guess. )
The below code is what came up with, but it fails to work, since the image comes out with a black background.
If anyone could tell me what I'm missing or doing incorrectly, or has any suggestions, please take a look and see if something comes to mind. Any help would be great.
#Include, Gdip.ahk ; DrawIconEx diFlags ; DI_MASK := 0x0001 DI_IMAGE := 0x0002 DI_NORMAL := 0x0003 ; BitBlt dwRop (Raster) ; SRCAND := 0x8800C6 SRCCOPY := 0xCC0020 SRCINVERT := 0x660046 ; Location of file containing icon etc. ; Width := 255 Height := 255 Filename := "C:\Windows\system32\cabview.dll" IconNumber := 1 IconSize := 255 ; Start gdi+ ; If !pToken := Gdip_Startup() { MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system ExitApp } ; Get icon handle by extracting it ; hIcon := ExtractIcon(Filename, IconNumber, IconSize) ; Create CmpDC, DIB, and select them ; hdcMask := CreateCompatibleDC() hbmMask := CreateDIBSection(Width, Height, hdcMask, 1) obmMask := SelectObject(hdcMask, hbmMask) ; Draw icon into DC using DI_MASK ; ; this gives a b/w image of icon ; DllCall("DrawIconEx" , "uint", hdcMask , "int", 0 , "int", 0 , "uint", hIcon , "int", 0 , "int", 0 , "uint", 0 , "uint", 0 , "uint", DI_MASK) ; Clean up for MaskDC ; SelectObject(hdcMask, obmMask) DeleteDC(hdcMask) ; Create CmpDC, DIB, and select them ; hdcImage := CreateCompatibleDC() hbmImage := CreateDIBSection(Width, Height, hdcImage) obmImage := SelectObject(hdcImage, hbmImage) ; Draw icon again into another DC using DI_NORMAL ; ; this gives the image of icon with black background ; DllCall("DrawIconEx" , "uint", hdcImage , "int", 0 , "int", 0 , "uint", hIcon , "int", 0 , "int", 0 , "uint", 0 , "uint", 0 , "uint", DI_IMAGE) ; Clean up for ImageDC ; SelectObject(hdcImage, obmImage) DeleteDC(hdcImage) ; Create the DestinationDC, DIB, and select them ; hdcDest := CreateCompatibleDC() hbmDest := CreateDIBSection(Width, Height, hdcDest) obmDest := SelectObject(hdcDest, hbmDest) ; BitBlt Image, Mask, and Image again into Destination DC ; ; This "should" make the black background transparent using ; ; these raster drawing, but not working... ; BitBlt(hdcDest, 0, 0, width, height, hdcImage, 0, 0, SRCINVERT) BitBlt(hdcDest, 0, 0, width, height, hdcMask, 0, 0, SRCAND) BitBlt(hdcDest, 0, 0, width, height, hdcImage, 0, 0, SRCINVERT) ; Clean up for DestinationDC ; SelectObject(hdcDest, obmDest) DeleteDC(hdcDest) ; Create a bitmap from the Destination bm handle ; pBitmap := Gdip_CreateBitmapFromHBITMAP(hbmDest) ; Save Bitmap to file ; Gdip_SaveBitmapToFile(pBitmap, "File.png") ; Clean up all bm created ; DeleteObject(hbmMask) DeleteObject(hbmImage) DeleteObject(hbmDest) Gdip_DisposeImage(pBitmap) ;Shut down GDI ; Gdip_Shutdown(pToken) Return F8:: Reload Return ; ExtractIcon functions courtesy of LEXIKOS ; ExtractIcon(Filename, IconNumber, IconSize=0) { static SmallIconSize, LargeIconSize if (!SmallIconSize) { SysGet, SmallIconSize, 49 ; 49, 50 SM_CXSMICON, SM_CYSMICON SysGet, LargeIconSize, 11 ; 11, 12 SM_CXICON, SM_CYICON } VarSetCapacity(phicon, 4, 0) h_icon = 0 ; If possible, use PrivateExtractIcons, which supports any size of icon. if A_OSVersion in WIN_VISTA,WIN_2003,WIN_XP,WIN_2000 { VarSetCapacity(piconid, 4, 0) ; MSDN: "... this function is deprecated ..." (oh well) ret := DllCall("PrivateExtractIcons" , "str", Filename , "int", IconNumber-1 ; zero-based index of the first icon to extract , "int", IconSize , "int", IconSize , "str", phicon ; pointer to an array of icon handles... , "str", piconid ; piconid - won't be used , "uint", 1 ; nIcons - number of icons to extract , "uint", 0, "uint") ; flags if (ret && ret != 0xFFFFFFFF) h_icon := NumGet(phicon) } else { ; Use ExtractIconEx, which only returns 16x16 or 32x32 icons. VarSetCapacity(phiconSmall, 4, 0) ; Extract the icon from an executable, DLL or icon file. if DllCall("shell32.dll\ExtractIconExA" , "str", Filename , "int", IconNumber-1 ; zero-based index of the first icon to extract , "str", phicon ; pointer to an array of icon handles... , "str", phiconSmall , "uint", 1) { ; Use the best-fit size; clean up the other. if (IconSize <= SmallIconSize) { DllCall("DestroyIcon", "uint", NumGet(phicon)) h_icon := NumGet(phiconSmall) } else { DllCall("DestroyIcon", "uint", NumGet(phiconSmall)) h_icon := NumGet(phicon) } } } return h_icon } GetIconSize(h_icon, ByRef width, ByRef height) { VarSetCapacity(ii, 20, 0) if (DllCall("GetIconInfo", "UInt", h_icon, "UInt", &ii)) { hbmColor := NumGet(ii, 16) hbmMask := NumGet(ii, 12) ret := GetBitmapSize(hbmColor, width, height) DllCall("DeleteObject", "UInt", hbmColor) DllCall("DeleteObject", "UInt", hbmMask) return ret } return false } GetBitmapSize(h_bitmap, ByRef width, ByRef height, ByRef bpp="") { VarSetCapacity(bm, 24, 0) ; BITMAP if (!DllCall("GetObject", "UInt", h_bitmap, "Int", 24, "UInt", &bm)) return false width := NumGet(bm, 4, "int") height := NumGet(bm, 8, "int") bpp := NumGet(bm,18, "ushort") return true }