smashly Posted September 18, 2009 Posted September 18, 2009 (edited) Hi, While playing around with GDIPlus I was wondering how to save a non transperent image as a png with transparency. Pretty sure it's been done before , but thought I'd post an unpolished/uncommented/no error checking example anyway expandcollapse popup#include <GDIPlus.au3> Global $sRegPath, $sImageIn, $sImageOut $sRegPath = "HKLM\SOFTWARE\AutoIt v3\AutoIt" If StringInStr("X64IA64", @OSArch) Then $sRegPath = StringReplace($sRegPath, "SOFTWARE", "SOFTWARE\Wow6432Node") $sImageIn = RegRead($sRegPath, "InstallDir") & "\Examples\GUI\logo4.gif" $sImageOut = @ScriptDir & "\Trans_logo4.png" _ImageToTransPNG($sImageIn, $sImageOut) If FileExists($sImageOut) Then ShellExecute($sImageOut) Func _ImageToTransPNG($sInFile, $sOutFile, $iXPixel = 0, $iYPixel = 0) Local $hImage, $iW, $iH, $iFirstPixel, $iTransPixel, $tBitmapData, $iStride, $iScan0, $iX, $iY, $tPixel, $iPixel Local $v_BufferA, $AllPixels, $sREResult1, $sPix _GDIPlus_Startup() $hImage = _GDIPlus_ImageLoadFromFile($sInFile) $iW = _GDIPlus_ImageGetWidth($hImage) $iH = _GDIPlus_ImageGetHeight($hImage) ;=> Start Work araound For XP, GDIPBitmapLockBits() seem to hard crash autoit When using images that are less then 24bpp ; If your using Vista or Newer OS then this won't be called or needed. If StringInStr('"WIN_2003","WIN_XP","WIN_2000"', @OSVersion) Then Local $aRet, $hBmp, $hBitmap, $hGraphic $aRet = _GDIPlus_ImageGetPixelFormat($hImage) If Int(StringRegExpReplace($aRet[1], "\D+", "")) < 24 Then $hBmp = _WinAPI_CreateBitmap($iW, $iH, 1, 32) $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hBmp) _WinAPI_DeleteObject($hBmp) $hGraphic = _GDIPlus_ImageGetGraphicsContext($hBitmap) _GDIPlus_GraphicsDrawImage($hGraphic, $hImage, 0, 0) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_ImageDispose($hImage) $hImage = _GDIPlus_BitmapCloneArea($hBitmap, 0, 0, $iW, $iH, $GDIP_PXF32ARGB) _GDIPlus_BitmapDispose($hBitmap) EndIf EndIf ;=> End Work around $tBitmapData = _GDIPlus_BitmapLockBits($hImage, 0, 0, $iW, $iH, $GDIP_ILMWRITE, $GDIP_PXF32ARGB) $iStride = DllStructGetData($tBitmapData, "stride") $iScan0 = DllStructGetData($tBitmapData, "Scan0") ; Get Pixel colour to be transparent at coordinates ($iXPixel, $iYPixel). $tPixel = DllStructCreate("int", $iScan0 + ($iYPixel * $iStride) + ($iXPixel * 4)) $iFirstPixel = DllStructGetData($tPixel, 1) $iTransPixel = BitAND($iFirstPixel, 0x00FFFFFF) $iFirstPixel = StringRegExpReplace(Hex($iFirstPixel, 8), "(.{2})(.{2})(.{2})(.{2})", "\4\3\2\1") ConsoleWrite($iFirstPixel & @LF) $iTransPixel = StringTrimRight($iFirstPixel, 2) & "00" $v_BufferA = DllStructCreate("byte[" & $iH * $iW * 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, $sOutFile, _GDIPlus_EncodersGetCLSID("PNG")) _GDIPlus_ImageDispose($hImage) _GDIPlus_Shutdown() EndFunc ;==>_ImageToTransPNG It appaers that <24bpp images and _GDIPlus_BitmapLockBits() in XP crash AutoIt when calling $GDIP_ILMWRITE. As a dirty work around I wrote in a check that should resolve it. Cheers Edit: Malkey did a nice example, posted his code, as it's faster and functional. Nice one Malkey Edited September 23, 2009 by smashly
UEZ Posted September 18, 2009 Posted September 18, 2009 Thanks for sharing Mr. GDI+ ;-) but AutoIt is crashing when running the code. No em in the console window! 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
UEZ Posted September 18, 2009 Posted September 18, 2009 Probably this is causing the crash (line 34-40). ... For $iX = 0 To $iW - 1 For $iY = 0 To $iH - 1 $tPixel = DllStructCreate("int", $iScan0 + ($iY * $iStride) + ($iX * 4)) $iPixel = DllStructGetData($tPixel, 1) If $iPixel = $iFirstPixel Then DllStructSetData($tPixel, 1, $iTransPixel) Next Next ... 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
smashly Posted September 18, 2009 Author Posted September 18, 2009 Probably this is causing the crash (line 34-40). ... For $iX = 0 To $iW - 1 For $iY = 0 To $iH - 1 $tPixel = DllStructCreate("int", $iScan0 + ($iY * $iStride) + ($iX * 4)) $iPixel = DllStructGetData($tPixel, 1) If $iPixel = $iFirstPixel Then DllStructSetData($tPixel, 1, $iTransPixel) Next Next ... UEZ Nope that's not it at all... I'm using win 7 x 64 and I don't have a problem with the code.. XP x86 that's another kettle of fish.. FFS... I found where it errors.. $tBitmapData = _GDIPlus_BitmapLockBits($hImage, 0, 0, $iW, $iH, $GDIP_ILMWRITE, $GDIP_PXF32ARGB) returns @error 2 under xp ... wtf.. But that only happens when using a gif file.. @error 2 = InvalidParameter 2 x wtf... Yet I load a jpg, png, bmp as an input file and xp works fine o_0 There is nothing wrong with the params.. I just checked MSDN and it even says that the $iFormat in _GDIPlus_BitmapLockBits() function does not have to be the same format as the image as your locking. Glad I moved on to win 7 x64 as I'm sorta tired of battling with xp x86 and it's quirks with autoit.. All I can suggest if you'd like to see it work is try the function with different input image format.. eg: png, jpg, bmp.. Cheers
UEZ Posted September 18, 2009 Posted September 18, 2009 Yes, with another image it worked properly! 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!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ
smashly Posted September 22, 2009 Author Posted September 22, 2009 Worked out why it was crashing in xp.. It appaers that <24bpp images and _GDIPlus_BitmapLockBits() in XP crash AutoIt when calling $GDIP_ILMWRITE. Added dirty work around when the code is run on XP. Cheers
Malkey Posted September 22, 2009 Posted September 22, 2009 Some possible alternatives for your consideration. 1/ Within the load Gif file in xp work around, this example uses _GDIPlus_BitmapCloneArea() instead of saving the gif image as a png file to disk. 2/ Removed _GDIPlus_BitmapGetPixel(). All pixels are already accessible when _GDIPlus_BitmapLockBits() is called. 3/ Instead of the two nested For- Next statements, StringRegExpReplace() is used which appears to be about three times faster. expandcollapse popup; #include <GDIPlus.au3> Global $sRegPath, $sImageIn, $sImageOut $sRegPath = "HKLM\SOFTWARE\AutoIt v3\AutoIt" If StringInStr("X64IA64", @OSArch) Then $sRegPath = StringReplace($sRegPath, "SOFTWARE", "SOFTWARE\Wow6432Node") $sImageIn = RegRead($sRegPath, "InstallDir") & "\Examples\GUI\logo4.gif" $sImageOut = @ScriptDir & "\Trans_logo4.png" _ImageToTransPNG($sImageIn, $sImageOut) If FileExists($sImageOut) Then ShellExecute($sImageOut) Func _ImageToTransPNG($sInFile, $sOutFile, $iXPixel = 0, $iYPixel = 0) Local $hImage, $iW, $iH, $iFirstPixel, $iTransPixel, $tBitmapData, $iStride, $iScan0, $iX, $iY, $tPixel, $iPixel Local $sXP_24bpp = @ScriptDir & "\XP_24bpp.png" _GDIPlus_Startup() $hImage = _GDIPlus_ImageLoadFromFile($sInFile) $iW = _GDIPlus_ImageGetWidth($hImage) $iH = _GDIPlus_ImageGetHeight($hImage) ;=> Start Work araound For XP, GDIPBitmapLockBits() seem to hard crash autoit When using images that are less then 24bpp ; If your using Vista or Newer OS then this won't be called or needed. If StringInStr("WIN_2003,WIN_XP,WIN_2000", @OSVersion) Then Local $aRet, $hBmp, $hBitmap, $hGraphic $aRet = _GDIPlus_ImageGetPixelFormat($hImage) If Int(StringRegExpReplace($aRet[1], "\D+", "")) < 24 Then $hBmp = _WinAPI_CreateBitmap($iW, $iH, 1, 32) $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hBmp) _WinAPI_DeleteObject($hBmp) $hGraphic = _GDIPlus_ImageGetGraphicsContext($hBitmap) _GDIPlus_GraphicsDrawImage($hGraphic, $hImage, 0, 0) _GDIPlus_ImageDispose($hImage) _GDIPlus_GraphicsDispose($hGraphic) $hImage = _GDIPlus_BitmapCloneArea($hBitmap, 0, 0, $iW, $iH, $GDIP_PXF32ARGB) _GDIPlus_BitmapDispose($hBitmap) EndIf EndIf ;=> End Work around $tBitmapData = _GDIPlus_BitmapLockBits($hImage, 0, 0, $iW, $iH, $GDIP_ILMWRITE, $GDIP_PXF32ARGB) $iStride = DllStructGetData($tBitmapData, "stride") $iScan0 = DllStructGetData($tBitmapData, "Scan0") ; Get Pixel colour to be transparent at coordinates ($iXPixel, $iYPixel). $tPixel = DllStructCreate("int", $iScan0 + ($iYPixel * $iStride) + ($iXPixel * 4)) $iFirstPixel = DllStructGetData($tPixel, 1) $iTransPixel = BitAND($iFirstPixel, 0x00FFFFFF) Local $begin = TimerInit() #cs For $iX = 0 To $iW - 1 For $iY = 0 To $iH - 1 $tPixel = DllStructCreate("int", $iScan0 + ($iY * $iStride) + ($iX * 4)) $iPixel = DllStructGetData($tPixel, 1) If $iPixel = $iFirstPixel Then DllStructSetData($tPixel, 1, $iTransPixel) Next Next #ce ;#cs $iFirstPixel = StringRegExpReplace(Hex($iFirstPixel, 8), "(.{2})(.{2})(.{2})(.{2})", "\4\3\2\1") $iTransPixel = StringTrimRight($iFirstPixel, 2) & "00" Local $v_BufferA = DllStructCreate("byte[" & $iH * $iW * 4 & "]", $iScan0) ; Create DLL structure for all pixels Local $AllPixels = DllStructGetData($v_BufferA, 1) Local $sREResult1 = StringRegExpReplace(StringTrimLeft($AllPixels, 2), "(.{8})", "\1 ") Local $sPix = "0x" & StringStripWS(StringRegExpReplace($sREResult1, "(" & $iFirstPixel & ")", $iTransPixel), 8) $AllPixels = DllStructSetData($v_BufferA, 1, $sPix) ;#ce _GDIPlus_BitmapUnlockBits($hImage, $tBitmapData) ConsoleWrite("Time: " & TimerDiff($begin) & @CRLF) _GDIPlus_ImageSaveToFileEx($hImage, $sOutFile, _GDIPlus_EncodersGetCLSID("PNG")) _GDIPlus_ImageDispose($hImage) _GDIPlus_Shutdown() If FileExists($sXP_24bpp) Then FileDelete($sXP_24bpp) EndFunc ;==>_ImageToTransPNG ;
Dolemite50 Posted November 17, 2009 Posted November 17, 2009 Looking good, gentlemen!Now who wants to bring it on home with "_ExtractIconToTransparentPng.au3"? Homer Simpson voice: "Hauuughhhhh iconnn to pnggggggg"
Xwolf1 Posted April 14, 2015 Posted April 14, 2015 (edited) Thanks for your code. Good job. Edited April 8, 2016 by Xwolf1
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now