Jump to content

Extracting icons into gdi with alpha channel


Recommended Posts

Func ExtractIcons($file, $folder, $output)
    $Ret = DllCall("shell32","long","ExtractAssociatedIcon","int",0,"str",$file,"int*",(-1*-1)-1)
    $hIcon = $Ret[0]
    _GDIPlus_Startup()
            $pBitmap = DllCall($ghGDIPDll,"int","GdipCreateBitmapFromHICON", "ptr",$hIcon, "int*",0)
            $pBitmap = $pBitmap[2]
    _GDIPlus_ImageSaveToFileEx($pBitmap,@ScriptDir&"\temp\images\"&$folder&$output&".png", _GDIPlus_EncodersGetCLSID("PNG"))
    _GDIPlus_ImageDispose($pBitmap)
    _GDIPlus_Shutdown()
    _WinAPI_DestroyIcon($hIcon)
    ;
    return @ScriptDir&"\temp\images\"&$folder&$output&".png"
EndFunc

The above function will extract an icon from any file I need and save it as a png. But GDI won't load in the alpha channel for the icon. My understanding is that this is a known issue.

I read somewhere that you could use the shell32.dll function "SHGetFileInfo" in order to get the alpha channel into gdi and then paint the color over it, but that is so very much beyond my comprehension or capabilites.

Anybody have an ideas? Has anybody done this sucessfully?

PS: The png I get from the icons do have transparency but it's like a gif in that it only has either opaque or non-opaque, there is no in between.

EDIT: To better clarify what I mean I basically need my function to extract the icons as it already does but additionally with the icons alpha channel so my pngs can keep intact the effect which incorporate variable transparency such as the shadows and the like.

Edited by JohnnyThrash
Link to comment
Share on other sites

Did you try HICON to .ico file already?

BR,

UEZ

Yes, i have looked at this code previously. However, I'm not sure it will do the trick. The code in the link seems to rely on the icon being saved as an icon and not png. Maybe it's exactly what I'm looking for but I don't think. Thanks for your help though. I think the key is probably going to be in dealing with GDI but i don't know exactly how.
Link to comment
Share on other sites

I found this in my collection:

...
            ;transparent code by smashly / Malkey - modified by UEZ
            $hImage = _GDIPlus_BitmapCloneArea($Bitmap, 0, 0, $w, $h, $GDIP_PXF32ARGB)
            $tBitmapData = _GDIPlus_BitmapLockBits($hImage, 0, 0, $w, $h, $GDIP_ILMWRITE, $GDIP_PXF32ARGB)

            $iStride = DllStructGetData($tBitmapData, "stride")
            $iScan0 = DllStructGetData($tBitmapData, "Scan0")
            $tPixel = DllStructCreate("int", $iScan0 + (0 * $iStride) + (0 * 4))

            $iFirstPixel = DllStructGetData($tPixel, 1)
            $iTransPixel = BitAND($iFirstPixel, 0x00FFFFFF)

            $iFirstPixel = StringRegExpReplace(Hex($iFirstPixel, 8), "(.{2})(.{2})(.{2})(.{2})", "\4\3\2\1")
            $iTransPixel = StringTrimRight($iFirstPixel, 2) & "00"
            $v_BufferA = DllStructCreate("byte[" & $h * $w * 4 & "]", $iScan0) ; Create DLL structure for all pixels
            $AllPixels = DllStructGetData($v_BufferA, 1)
            $sREResult1 = StringRegExpReplace(StringTrimLeft($AllPixels, 2), "(.{8})", "\1 ")
            $sPix = "0x" & StringStripWS(StringRegExpReplace($sREResult1, "(" & $iFirstPixel & ")", $iTransPixel), 8)
            $AllPixels = DllStructSetData($v_BufferA, 1, $sPix)

            _GDIPlus_BitmapUnlockBits($hImage, $tBitmapData)
            _GDIPlus_ImageSaveToFileEx($hImage, @ScriptDir & "\Test.PNG", _GDIPlus_EncodersGetCLSID("PNG"))
            _GDIPlus_ImageDispose($hImage)
...

Maybe this will help you. It will create a transparency and save it as png.

BR,

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

Here the example with your code from 1st post:

#include <GDIPlus.au3>
ExtractIcons("Test.exe")

Func ExtractIcons($file)
    $Ret = DllCall("shell32","long","ExtractAssociatedIcon","int",0,"str",$file,"int*",(-1*-1)-1)
    $hIcon = $Ret[0]
    _GDIPlus_Startup()
    $Bitmap = DllCall($ghGDIPDll,"int","GdipCreateBitmapFromHICON", "ptr",$hIcon, "int*",0)
    $Bitmap = $Bitmap[2]
    $w = _GDIPlus_ImageGetWidth($Bitmap)
    $h = _GDIPlus_ImageGetHeight($Bitmap)
    ;transparent code by smashly / Malkey - modified by UEZ
    $hImage = _GDIPlus_BitmapCloneArea($Bitmap, 0, 0, $w, $h, $GDIP_PXF32ARGB)
    $tBitmapData = _GDIPlus_BitmapLockBits($hImage, 0, 0, $w, $h, $GDIP_ILMWRITE, $GDIP_PXF32ARGB)

    $iStride = DllStructGetData($tBitmapData, "stride")
    $iScan0 = DllStructGetData($tBitmapData, "Scan0")
    $tPixel = DllStructCreate("int", $iScan0 + (0 * $iStride) + (0 * 4))

    $iFirstPixel = DllStructGetData($tPixel, 1)
    $iTransPixel = BitAND($iFirstPixel, 0x00FFFFFF)

    $iFirstPixel = StringRegExpReplace(Hex($iFirstPixel, 8), "(.{2})(.{2})(.{2})(.{2})", "\4\3\2\1")
    $iTransPixel = StringTrimRight($iFirstPixel, 2) & "00"
    $v_BufferA = DllStructCreate("byte[" & $h * $w * 4 & "]", $iScan0) ; Create DLL structure for all pixels
    $AllPixels = DllStructGetData($v_BufferA, 1)
    $sREResult1 = StringRegExpReplace(StringTrimLeft($AllPixels, 2), "(.{8})", "\1 ")
    $sPix = "0x" & StringStripWS(StringRegExpReplace($sREResult1, "(" & $iFirstPixel & ")", $iTransPixel), 8)
    $AllPixels = DllStructSetData($v_BufferA, 1, $sPix)

    _GDIPlus_BitmapUnlockBits($hImage, $tBitmapData)
    _GDIPlus_ImageSaveToFileEx($hImage, @ScriptDir & "\Test.PNG", _GDIPlus_EncodersGetCLSID("PNG"))
    _GDIPlus_ImageDispose($hImage)

    _GDIPlus_Shutdown()
    _WinAPI_DestroyIcon($hIcon)
    ;
    return 1
EndFunc

Please try it with a transparent icon!

BR,

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

I found this in my collection:

...
            ;transparent code by smashly / Malkey - modified by UEZ
            $hImage = _GDIPlus_BitmapCloneArea($Bitmap, 0, 0, $w, $h, $GDIP_PXF32ARGB)
            $tBitmapData = _GDIPlus_BitmapLockBits($hImage, 0, 0, $w, $h, $GDIP_ILMWRITE, $GDIP_PXF32ARGB)

            $iStride = DllStructGetData($tBitmapData, "stride")
            $iScan0 = DllStructGetData($tBitmapData, "Scan0")
            $tPixel = DllStructCreate("int", $iScan0 + (0 * $iStride) + (0 * 4))

            $iFirstPixel = DllStructGetData($tPixel, 1)
            $iTransPixel = BitAND($iFirstPixel, 0x00FFFFFF)

            $iFirstPixel = StringRegExpReplace(Hex($iFirstPixel, 8), "(.{2})(.{2})(.{2})(.{2})", "\4\3\2\1")
            $iTransPixel = StringTrimRight($iFirstPixel, 2) & "00"
            $v_BufferA = DllStructCreate("byte[" & $h * $w * 4 & "]", $iScan0) ; Create DLL structure for all pixels
            $AllPixels = DllStructGetData($v_BufferA, 1)
            $sREResult1 = StringRegExpReplace(StringTrimLeft($AllPixels, 2), "(.{8})", "\1 ")
            $sPix = "0x" & StringStripWS(StringRegExpReplace($sREResult1, "(" & $iFirstPixel & ")", $iTransPixel), 8)
            $AllPixels = DllStructSetData($v_BufferA, 1, $sPix)

            _GDIPlus_BitmapUnlockBits($hImage, $tBitmapData)
            _GDIPlus_ImageSaveToFileEx($hImage, @ScriptDir & "\Test.PNG", _GDIPlus_EncodersGetCLSID("PNG"))
            _GDIPlus_ImageDispose($hImage)
...

Maybe this will help you. It will create a transparency and save it as png.

BR,

UEZ

I have to admit, I don't actually understand you code entirely. Also, I had to change the $W and $h to 32, since they weren't defined.

Here's the code I came up with but it still produces the same results as before. As I've mentioned before I can sucessfully get a png from the icon with a transparent background, however I cannot get any variable transparency.

Func ExtractIcons($file, $folder, $output)
    $Ret = DllCall("shell32","long","ExtractAssociatedIcon","int",0,"str",$file,"int*",(-1*-1)-1)
    ;$hIcon=getIconHandleByFile($file)
    $hIcon = $Ret[0]
    _GDIPlus_Startup()
            $pBitmap = DllCall($ghGDIPDll,"int","GdipCreateBitmapFromHICON", "ptr",$hIcon, "int*",0)
            $pBitmap = $pBitmap[2]
                    ;transparent code by smashly / Malkey - modified by UEZ
            $hImage = _GDIPlus_BitmapCloneArea($pBitmap, 0, 0, 32, 32, $GDIP_PXF32ARGB)
            $tBitmapData = _GDIPlus_BitmapLockBits($hImage, 0, 0, 32, 32, $GDIP_ILMWRITE, $GDIP_PXF32ARGB)

            $iStride = DllStructGetData($tBitmapData, "stride")
            $iScan0 = DllStructGetData($tBitmapData, "Scan0")
            $tPixel = DllStructCreate("int", $iScan0 + (0 * $iStride) + (0 * 4))

            $iFirstPixel = DllStructGetData($tPixel, 1)
            $iTransPixel = BitAND($iFirstPixel, 0x00FFFFFF)

            $iFirstPixel = StringRegExpReplace(Hex($iFirstPixel, 8), "(.{2})(.{2})(.{2})(.{2})", "\4\3\2\1")
            $iTransPixel = StringTrimRight($iFirstPixel, 2) & "00"
            $v_BufferA = DllStructCreate("byte[" & 32 * 32 * 4 & "]", $iScan0) ; Create DLL structure for all pixels
            $AllPixels = DllStructGetData($v_BufferA, 1)
            $sREResult1 = StringRegExpReplace(StringTrimLeft($AllPixels, 2), "(.{8})", "\1 ")
            $sPix = "0x" & StringStripWS(StringRegExpReplace($sREResult1, "(" & $iFirstPixel & ")", $iTransPixel), 8)
            $AllPixels = DllStructSetData($v_BufferA, 1, $sPix)

            _GDIPlus_BitmapUnlockBits($hImage, $tBitmapData)
            _GDIPlus_ImageSaveToFileEx($hImage, @ScriptDir&"\temp\images\"&$folder&$output&".png", _GDIPlus_EncodersGetCLSID("PNG"))
            _GDIPlus_ImageDispose($hImage)
    return @ScriptDir&"\temp\images\"&$folder&$output&".png"
EndFunc

I hope I'm not being a pain in the ass.

Link to comment
Share on other sites

What are "variable transparency" icons?

Can you upload one?

BR,

UEZ

Well, really, I'm just throwing that term around. It means that there are varying levels of opacity. There's not just see-through and solid. There's also amounts in between.

An example of an icon i can extract is this:

Posted Image

You might be familiar with this icon. However, the icon you've seen has a subtle drop shadow effect, only here instead you see a thick black outline. That black area is an area that would be slightly see through but not entirely opaque or otherwise.

Link to comment
Share on other sites

Link to comment
Share on other sites

Well that's exactly the way i understand it. When GDI loads an icon it does not load the alpha channel or it discards it.

I have a concept, but I have no idea how to execute it. What if i got just the alpha channel and looped through all the pixels in the icon setting each to have the opacity that corresponds to the alpha channel? I've seen this done in other languages but not Autoit. Any ideas?

Link to comment
Share on other sites

  • Moderators

I've seen this done in other languages but not Autoit. Any ideas?

It might be good to post the code you know works in other languages so someone can help you translate it to AutoIt?

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Link to comment
Share on other sites

It might be good to post the code you know works in other languages so someone can help you translate it to AutoIt?

Good idea, sorry, I should have thought of that.

Below is a excerp from the following link : http://groups.google.com.ar/group/microsoft.public.win32.programmer.gdi/msg/fa5de1f2bc9a04d3

I believe a translation of the following code *may* do what I am hoping.

and for what it's worth, I have looked into doing the task myself but some of this goes way over my head (That's why I use autoit instead of a more complicated language =P)

The Solution was to Get the ICONINFO from the icon, Create a bitmap using

the ICONINFO’s bitmap handle, get the BitmapData from it, and use the

BitmapData to create another bitmap which has the alpha channel.

//get the icon info

ICONINFO ii;

GetIconInfo(hIcon, &ii);

//create a bitmap from the ICONINFO so we can access the bitmapData

Bitmap bmpIcon(ii.hbmColor, NULL);

Rect rectBounds(0, 0, bmpIcon.GetWidth(), bmpIcon.GetHeight() );

//get the BitmapData

BitmapData bmData;

bmpIcon.LockBits(&rectBounds, ImageLockModeRead,

bmpIcon.GetPixelFormat(), &bmData);

// create a new 32 bit bitmap using the bitmapData

Bitmap bmpAlpha(bmData.Width, bmData.Height, bmData.Stride,

PixelFormat32bppARGB, (BYTE*)bmData.Scan0);

bmpIcon.UnlockBits(&bmData);

Now we have the icon with the alpha channel loaded into bmpAlpha!

Note: my code only works for icons with an alpha channel.

This solves my problem but it seems strange to me that directly creating a

Bitmap from an HICON cusses the Alpha channel to be lost. Am I not

understanding something, or is it possibly a bug?. If anyone can explain

this I would love to know the reason.

Another solution might be found here as well,

http://blogs.msdn.com/b/andreww/archive/2007/10/10/preserving-the-alpha-channel-when-converting-images.aspx

Edited by JohnnyThrash
Link to comment
Share on other sites

UPDATE: I've also found this on the autohotkey forums. I hope this isn't taboo or anything =S.

I figured since AutoHotKey and AutoIt were so similar this might help.

The only issue is it's not entirely clear to me how the solution provided in this topic is applied.

If anybody could offer any insight on this I would very much appreciate it.

http://www.autohotkey.com/forum/topic53775.html

(PS: I hope that in this situation double posting is not frowned upon. I figured if I merely had edit my last post people that may have previously read it would not notice there was updated content, hence this additional post... not to mention it's been quite a few days.)

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