Single-image ico to png, but under XP

Get help with using AutoHotkey and its commands and hotkeys
Zvonko
Posts: 210
Joined: 19 Jun 2015, 11:52

Single-image ico to png, but under XP

20 Nov 2015, 14:28

The script below converts single-image ico files to png files without the lost of transparency.

However, the method is working only on newer Windows versions. On XP it is working only with single-image icons up to 48 px.

As a AHK newbie I suppose that the functions are dependent on the displaying capabilities of Windows: Under XP only icons up to 48 px can be displayed.

Should a guru see a possibility to overcome this limitation...

Code: Select all

#NoEnv
SendMode Input  
SetWorkingDir %A_ScriptDir% 
SetBatchLines, -1

; #Warn


pToken := Gdip_Startup()


Gui Info: -dpiscale
Gui Info: Add, Text, y25, This script demonstrates how a png file can be created
Gui Info: Add, Text, yp+18, from a single-image ico file.
Gui Info: Add, Text, yp+48, Press F6 to select a file.
Gui Info: Show, x20 y20 w400 h150

RETURN


F6::
FileSelectFile, IcoF, , %A_ScriptDir%\*.*, Select a single-image ico file
   If ErrorLevel
      return
SplitPath, IcoF, , , ,IName
PngF := A_ScriptDir . "\" IName . ".png"

SingleImageIco2Png(IcoF, PngF)

ShowGui(PngF)

Gdip_Shutdown(pToken)
return



ShowGui(IcoF)		
{
global
   Gui, Destroy

   Loop, Files, %A_WinDir%\Web\Wallpaper\*.jpg, FR
	{
   	BkgPic := A_LoopFileLongPath
   	Break
	}

;BkgPic = %A_ScriptDir%\BackGImage.jpg

   Gui, -dpiscale
   Gui, Margin, 0, 0
   Gui, Color, Navy		
   Gui, Add, Picture, w800 h800 vBkg, %BkgPic%

   Gui, Add, Picture, x30 y30 w32 h32 AltSubmit BackGroundTrans, %PngF%
   Gui, Add, Picture, x110 y30 w48 h48 AltSubmit BackGroundTrans, %PngF%
   Gui, Add, Picture, x215 y30 w64 h64 AltSubmit BackGroundTrans, %PngF%
   Gui, Add, Picture, x345 y30 w128 h128 AltSubmit BackGroundTrans, %PngF%
   Gui, Add, Picture, x525 y30 w256 h256 AltSubmit BackGroundTrans, %PngF%
   Gui, Font, cWhite s12
   Gui, Add, Text, x30 y300, png-file: %PngF%
   Gui, Show, x100 y100, IcoPicture
}


InfoGuiClose:
Gdip_Shutdown(pToken)
ExitApp


; ####################################################################################
										;#####
SingleImageIco2Png(Filename, sOutput)						;#####
{										;#####
   pBitmap := Gdip_CreateBitmapFromFile(FileName)				;#####
   Gdip_SaveBitmapToFile(pBitmap, sOutput)					;#####
   Gdip_DisposeImage(pBitmap)							;#####
}										;#####
										;#####
; ####################################################################################




;######################

Gdip_Startup()
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	if !DllCall("GetModuleHandle", "str", "gdiplus", Ptr)
		DllCall("LoadLibrary", "str", "gdiplus")
	VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
	DllCall("gdiplus\GdiplusStartup", A_PtrSize ? "UPtr*" : "uint*", pToken, Ptr, &si, Ptr, 0)
	return pToken
}


Gdip_Shutdown(pToken)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	DllCall("gdiplus\GdiplusShutdown", Ptr, pToken)
	if hModule := DllCall("GetModuleHandle", "str", "gdiplus", Ptr)
		DllCall("FreeLibrary", Ptr, hModule)
	return 0
}

;######################

Gdip_CreateBitmapFromFile(sFile, IconNumber=1, IconSize="")
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	, PtrA := A_PtrSize ? "UPtr*" : "UInt*"
	
	SplitPath, sFile,,, ext
	if ext in exe,dll,ico		; !!!!!!!!!!!!!!!!!! ADDED!!!
	{
		Sizes := IconSize ? IconSize : 256 "|" 128 "|" 64 "|" 48 "|" 32 "|" 16
		BufSize := 16 + (2*(A_PtrSize ? A_PtrSize : 4))
		
		VarSetCapacity(buf, BufSize, 0)
		Loop, Parse, Sizes, |
		{
			DllCall("PrivateExtractIcons", "str", sFile, "int", IconNumber-1, "int", 

A_LoopField, "int", A_LoopField, PtrA, hIcon, PtrA, 0, "uint", 1, "uint", 0)
			
			if !hIcon
				continue

			if !DllCall("GetIconInfo", Ptr, hIcon, Ptr, &buf)
			{
				DestroyIcon(hIcon)
				continue
			}
			
			hbmMask  := NumGet(buf, 12 + ((A_PtrSize ? A_PtrSize : 4) - 4))
			hbmColor := NumGet(buf, 12 + ((A_PtrSize ? A_PtrSize : 4) - 4) + (A_PtrSize ? 

A_PtrSize : 4))
			if !(hbmColor && DllCall("GetObject", Ptr, hbmColor, "int", BufSize, Ptr, 

&buf))
			{
				DestroyIcon(hIcon)
				continue
			}
			break
		}
		if !hIcon
			return -1

		Width := NumGet(buf, 4, "int"), Height := NumGet(buf, 8, "int")
		hbm := CreateDIBSection(Width, -Height), hdc := CreateCompatibleDC(), obm := 

SelectObject(hdc, hbm)
		if !DllCall("DrawIconEx", Ptr, hdc, "int", 0, "int", 0, Ptr, hIcon, "uint", Width, 

"uint", Height, "uint", 0, Ptr, 0, "uint", 3)
		{
			DestroyIcon(hIcon)
			return -2
		}
		
		VarSetCapacity(dib, 104)
		DllCall("GetObject", Ptr, hbm, "int", A_PtrSize = 8 ? 104 : 84, Ptr, &dib) ; sizeof

(DIBSECTION) = 76+2*(A_PtrSize=8?4:0)+2*A_PtrSize
		Stride := NumGet(dib, 12, "Int"), Bits := NumGet(dib, 20 + (A_PtrSize = 8 ? 4 : 0)) ; 

padding
		DllCall("gdiplus\GdipCreateBitmapFromScan0", "int", Width, "int", Height, "int", 

Stride, "int", 0x26200A, Ptr, Bits, PtrA, pBitmapOld)
		pBitmap := Gdip_CreateBitmap(Width, Height)
		G := Gdip_GraphicsFromImage(pBitmap)
		, Gdip_DrawImage(G, pBitmapOld, 0, 0, Width, Height, 0, 0, Width, Height)
		SelectObject(hdc, obm), DeleteObject(hbm), DeleteDC(hdc)
		Gdip_DeleteGraphics(G), Gdip_DisposeImage(pBitmapOld)
		DestroyIcon(hIcon)
	}
	else
	{
		if (!A_IsUnicode)
		{
			VarSetCapacity(wFile, 1024)
			DllCall("kernel32\MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sFile, 

"int", -1, Ptr, &wFile, "int", 512)
			DllCall("gdiplus\GdipCreateBitmapFromFile", Ptr, &wFile, PtrA, pBitmap)
		}
		else
			DllCall("gdiplus\GdipCreateBitmapFromFile", Ptr, &sFile, PtrA, pBitmap)
	}
	
	return pBitmap
}

;######################

Gdip_SaveBitmapToFile(pBitmap, sOutput, Quality=75)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	SplitPath, sOutput,,, Extension
	if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
		return -1
	Extension := "." Extension

	DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", nCount, "uint*", nSize)
	VarSetCapacity(ci, nSize)
	DllCall("gdiplus\GdipGetImageEncoders", "uint", nCount, "uint", nSize, Ptr, &ci)
	if !(nCount && nSize)
		return -2
	
	If (A_IsUnicode){
		StrGet_Name := "StrGet"
		Loop, %nCount%
		{
			sString := %StrGet_Name%(NumGet(ci, (idx := (48+7*A_PtrSize)*(A_Index-

1))+32+3*A_PtrSize), "UTF-16")
			if !InStr(sString, "*" Extension)
				continue
			
			pCodec := &ci+idx
			break
		}
	} else {
		Loop, %nCount%
		{
			Location := NumGet(ci, 76*(A_Index-1)+44)
			nSize := DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", 

Location, "int", -1, "uint", 0, "int",  0, "uint", 0, "uint", 0)
			VarSetCapacity(sString, nSize)
			DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", 

-1, "str", sString, "int", nSize, "uint", 0, "uint", 0)
			if !InStr(sString, "*" Extension)
				continue
			
			pCodec := &ci+76*(A_Index-1)
			break
		}
	}
	
	if !pCodec
		return -3

	if (Quality != 75)
	{
		Quality := (Quality < 0) ? 0 : (Quality > 100) ? 100 : Quality
		if Extension in .JPG,.JPEG,.JPE,.JFIF
		{
			DllCall("gdiplus\GdipGetEncoderParameterListSize", Ptr, pBitmap, Ptr, pCodec, 

"uint*", nSize)
			VarSetCapacity(EncoderParameters, nSize, 0)
			DllCall("gdiplus\GdipGetEncoderParameterList", Ptr, pBitmap, Ptr, pCodec, 

"uint", nSize, Ptr, &EncoderParameters)
			Loop, % NumGet(EncoderParameters, "UInt")      ;%
			{
				elem := (24+(A_PtrSize ? A_PtrSize : 4))*(A_Index-1) + 4 + (pad := 

A_PtrSize = 8 ? 4 : 0)
				if (NumGet(EncoderParameters, elem+16, "UInt") = 1) && (NumGet

(EncoderParameters, elem+20, "UInt") = 6)
				{
					p := elem+&EncoderParameters-pad-4
					NumPut(Quality, NumGet(NumPut(4, NumPut(1, p+0)+20, "UInt")), 

"UInt")
					break
				}
			}      
		}
	}

	if (!A_IsUnicode)
	{
		nSize := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sOutput, "int", 

-1, Ptr, 0, "int", 0)
		VarSetCapacity(wOutput, nSize*2)
		DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sOutput, "int", -1, Ptr, 

&wOutput, "int", nSize)
		VarSetCapacity(wOutput, -1)
		if !VarSetCapacity(wOutput)
			return -4
		E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, Ptr, &wOutput, Ptr, pCodec, 

"uint", p ? p : 0)
	}
	else
		E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, Ptr, &sOutput, Ptr, pCodec, 

"uint", p ? p : 0)
	return E ? -5 : 0
}

;######################

Gdip_DisposeImage(pBitmap)
{
   return DllCall("gdiplus\GdipDisposeImage", A_PtrSize ? "UPtr" : "UInt", pBitmap)
}

;######################

; Function				DestroyIcon
; Description			Destroys an icon and frees any memory the icon occupied
;
; hIcon					Handle to the icon to be destroyed. The icon must not be in 

use
;
; return				If the function succeeds, the return value is nonzero

DestroyIcon(hIcon)
{
	return DllCall("DestroyIcon", A_PtrSize ? "UPtr" : "UInt", hIcon)
}

;######################

; Function				CreateDIBSection
; Description			The CreateDIBSection function creates a DIB (Device Independent 

Bitmap) that applications can write to directly
;
; w						width of the bitmap to create
; h						height of the bitmap to create
; hdc					a handle to the device context to use the palette from
; bpp					bits per pixel (32 = ARGB)
; ppvBits				A pointer to a variable that receives a pointer to the 

location of the DIB bit values
;
; return				returns a DIB. A gdi bitmap
;
; notes					ppvBits will receive the location of the pixels in the DIB

CreateDIBSection(w, h, hdc="", bpp=32, ByRef ppvBits=0)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	hdc2 := hdc ? hdc : GetDC()
	VarSetCapacity(bi, 40, 0)
	
	NumPut(w, bi, 4, "uint")
	, NumPut(h, bi, 8, "uint")
	, NumPut(40, bi, 0, "uint")
	, NumPut(1, bi, 12, "ushort")
	, NumPut(0, bi, 16, "uInt")
	, NumPut(bpp, bi, 14, "ushort")
	
	hbm := DllCall("CreateDIBSection"
					, Ptr, hdc2
					, Ptr, &bi
					, "uint", 0
					, A_PtrSize ? "UPtr*" : "uint*", ppvBits
					, Ptr, 0
					, "uint", 0, Ptr)

	if !hdc
		ReleaseDC(hdc2)
	return hbm
}

;######################

; Function				CreateCompatibleDC
; Description			This function creates a memory device context (DC) compatible with 

the specified device
;
; hdc					Handle to an existing device context				

	
;
; return				returns the handle to a device context or 0 on failure
;
; notes					If this handle is 0 (by default), the function creates a 

memory device context compatible with the application's current screen

CreateCompatibleDC(hdc=0)
{
   return DllCall("CreateCompatibleDC", A_PtrSize ? "UPtr" : "UInt", hdc)
}

;######################

; Function				SelectObject
; Description			The SelectObject function selects an object into the specified device 

context (DC). The new object replaces the previous object of the same type
;
; hdc					Handle to a DC
; hgdiobj				A handle to the object to be selected into the DC
;
; return				If the selected object is not a region and the function 

succeeds, the return value is a handle to the object being replaced
;
; notes					The specified object must have been created by using one of 

the following functions
;						Bitmap - CreateBitmap, CreateBitmapIndirect, 

CreateCompatibleBitmap, CreateDIBitmap, CreateDIBSection (A single bitmap cannot be selected into 

more than one DC at the same time)
;						Brush - CreateBrushIndirect, CreateDIBPatternBrush, 

CreateDIBPatternBrushPt, CreateHatchBrush, CreatePatternBrush, CreateSolidBrush
;						Font - CreateFont, CreateFontIndirect
;						Pen - CreatePen, CreatePenIndirect
;						Region - CombineRgn, CreateEllipticRgn, 

CreateEllipticRgnIndirect, CreatePolygonRgn, CreateRectRgn, CreateRectRgnIndirect
;
; notes					If the selected object is a region and the function succeeds, 

the return value is one of the following value
;
; SIMPLEREGION			= 2 Region consists of a single rectangle
; COMPLEXREGION			= 3 Region consists of more than one rectangle
; NULLREGION			= 1 Region is empty

SelectObject(hdc, hgdiobj)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	return DllCall("SelectObject", Ptr, hdc, Ptr, hgdiobj)
}

;######################

Gdip_CreateBitmap(Width, Height, Format=0x26200A)
{
    DllCall("gdiplus\GdipCreateBitmapFromScan0", "int", Width, "int", Height, "int", 0, "int", 

Format, A_PtrSize ? "UPtr" : "UInt", 0, A_PtrSize ? "UPtr*" : "uint*", pBitmap)
    Return pBitmap
}

;######################

; Function				Gdip_GraphicsFromImage
; Description			This function gets the graphics for a bitmap used for drawing 

functions
;
; pBitmap				Pointer to a bitmap to get the pointer to its graphics
;
; return				returns a pointer to the graphics of a bitmap
;
; notes					a bitmap can be drawn into the graphics of another bitmap

Gdip_GraphicsFromImage(pBitmap)
{
	DllCall("gdiplus\GdipGetImageGraphicsContext", A_PtrSize ? "UPtr" : "UInt", pBitmap, 

A_PtrSize ? "UPtr*" : "UInt*", pGraphics)
	return pGraphics
}

;######################

; Function				Gdip_DrawImage
; Description			This function draws a bitmap into the Graphics of another bitmap
;
; pGraphics				Pointer to the Graphics of a bitmap
; pBitmap				Pointer to a bitmap to be drawn
; dx					x-coord of destination upper-left corner
; dy					y-coord of destination upper-left corner
; dw					width of destination image
; dh					height of destination image
; sx					x-coordinate of source upper-left corner
; sy					y-coordinate of source upper-left corner
; sw					width of source image
; sh					height of source image
; Matrix				a matrix used to alter image attributes when drawing
;
; return				status enumeration. 0 = success
;
; notes					if sx,sy,sw,sh are missed then the entire source bitmap will 

be used
;						Gdip_DrawImage performs faster
;						Matrix can be omitted to just draw with no alteration 

to ARGB
;						Matrix may be passed as a digit from 0 - 1 to change 

just transparency
;						Matrix can be passed as a matrix with any delimiter. 

For example:
;						MatrixBright=
;						(
;						1.5		|0		|0		|0	

	|0
;						0		|1.5	|0		|0		

|0
;						0		|0		|1.5	|0		

|0
;						0		|0		|0		|1	

	|0
;						0.05	|0.05	|0.05	|0		|1
;						)
;
; notes					MatrixBright = 1.5|0|0|0|0|0|1.5|0|0|0|0|0|1.5|0|0|0|0|0|1|

0|0.05|0.05|0.05|0|1
;						MatrixGreyScale = 0.299|0.299|0.299|0|0|0.587|0.587|

0.587|0|0|0.114|0.114|0.114|0|0|0|0|0|1|0|0|0|0|0|1
;						MatrixNegative = -1|0|0|0|0|0|-1|0|0|0|0|0|-1|0|0|0|

0|0|1|0|0|0|0|0|1

Gdip_DrawImage(pGraphics, pBitmap, dx="", dy="", dw="", dh="", sx="", sy="", sw="", sh="", Matrix=1)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	if (Matrix&1 = "")
		ImageAttr := Gdip_SetImageAttributesColorMatrix(Matrix)
	else if (Matrix != 1)
		ImageAttr := Gdip_SetImageAttributesColorMatrix("1|0|0|0|0|0|1|0|0|0|0|0|1|0|0|0|0|

0|" Matrix "|0|0|0|0|0|1")

	if (sx = "" && sy = "" && sw = "" && sh = "")
	{
		if (dx = "" && dy = "" && dw = "" && dh = "")
		{
			sx := dx := 0, sy := dy := 0
			sw := dw := Gdip_GetImageWidth(pBitmap)
			sh := dh := Gdip_GetImageHeight(pBitmap)
		}
		else
		{
			sx := sy := 0
			sw := Gdip_GetImageWidth(pBitmap)
			sh := Gdip_GetImageHeight(pBitmap)
		}
	}

	E := DllCall("gdiplus\GdipDrawImageRectRect"
				, Ptr, pGraphics
				, Ptr, pBitmap
				, "float", dx
				, "float", dy
				, "float", dw
				, "float", dh
				, "float", sx
				, "float", sy
				, "float", sw
				, "float", sh
				, "int", 2
				, Ptr, ImageAttr
				, Ptr, 0
				, Ptr, 0)
	if ImageAttr
		Gdip_DisposeImageAttributes(ImageAttr)
	return E
}

;######################

; Function				DeleteObject
; Description			This function deletes a logical pen, brush, font, bitmap, region, or 

palette, freeing all system resources associated with the object
;						After the object is deleted, the specified handle is 

no longer valid
;
; hObject				Handle to a logical pen, brush, font, bitmap, region, or 

palette to delete
;
; return				Nonzero indicates success. Zero indicates that the specified 

handle is not valid or that the handle is currently selected into a device context

DeleteObject(hObject)
{
   return DllCall("DeleteObject", A_PtrSize ? "UPtr" : "UInt", hObject)
}

;######################

; Function				DeleteDC
; Description			The DeleteDC function deletes the specified device context (DC)
;
; hdc					A handle to the device context
;
; return				If the function succeeds, the return value is nonzero
;
; notes					An application must not delete a DC whose handle was obtained 

by calling the GetDC function. Instead, it must call the ReleaseDC function to free the DC

DeleteDC(hdc)
{
   return DllCall("DeleteDC", A_PtrSize ? "UPtr" : "UInt", hdc)
}

;######################

Gdip_DeleteGraphics(pGraphics)
{
   return DllCall("gdiplus\GdipDeleteGraphics", A_PtrSize ? "UPtr" : "UInt", pGraphics)
}

;######################

; Function				GetDC
; Description			This function retrieves a handle to a display device context (DC) for 

the client area of the specified window.
;						The display device context can be used in subsequent 

graphics display interface (GDI) functions to draw in the client area of the window. 
;
; hwnd					Handle to the window whose device context is to be retrieved. 

If this value is NULL, GetDC retrieves the device context for the entire screen				

	
;
; return				The handle the device context for the specified window's 

client area indicates success. NULL indicates failure

GetDC(hwnd=0)
{
	return DllCall("GetDC", A_PtrSize ? "UPtr" : "UInt", hwnd)
}

;######################

; Function				ReleaseDC
; Description			This function releases a device context (DC), freeing it for use by 

other applications. The effect of ReleaseDC depends on the type of device context
;
; hdc					Handle to the device context to be released
; hwnd					Handle to the window whose device context is to be released
;
; return				1 = released
;						0 = not released
;
; notes					The application must call the ReleaseDC function for each 

call to the GetWindowDC function and for each call to the GetDC function that retrieves a common 

device context
;						An application cannot use the ReleaseDC function to 

release a device context that was created by calling the CreateDC function; instead, it must use the 

DeleteDC function. 

ReleaseDC(hdc, hwnd=0)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	return DllCall("ReleaseDC", Ptr, hwnd, Ptr, hdc)
}

;######################

; Function				Gdip_SetImageAttributesColorMatrix
; Description			This function creates an image matrix ready for drawing
;
; Matrix				a matrix used to alter image attributes when drawing
;						passed with any delimeter
;
; return				returns an image matrix on sucess or 0 if it fails
;
; notes					MatrixBright = 1.5|0|0|0|0|0|1.5|0|0|0|0|0|1.5|0|0|0|0|0|1|

0|0.05|0.05|0.05|0|1
;						MatrixGreyScale = 0.299|0.299|0.299|0|0|0.587|0.587|

0.587|0|0|0.114|0.114|0.114|0|0|0|0|0|1|0|0|0|0|0|1
;						MatrixNegative = -1|0|0|0|0|0|-1|0|0|0|0|0|-1|0|0|0|

0|0|1|0|0|0|0|0|1

Gdip_SetImageAttributesColorMatrix(Matrix)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	VarSetCapacity(ColourMatrix, 100, 0)
	Matrix := RegExReplace(RegExReplace(Matrix, "^[^\d-\.]+([\d\.])", "$1", "", 1), "[^\d-\.]+", 

"|")
	StringSplit, Matrix, Matrix, |
	Loop, 25
	{
		Matrix := (Matrix%A_Index% != "") ? Matrix%A_Index% : Mod(A_Index-1, 6) ? 0 : 1
		NumPut(Matrix, ColourMatrix, (A_Index-1)*4, "float")
	}
	DllCall("gdiplus\GdipCreateImageAttributes", A_PtrSize ? "UPtr*" : "uint*", ImageAttr)
	DllCall("gdiplus\GdipSetImageAttributesColorMatrix", Ptr, ImageAttr, "int", 1, "int", 1, Ptr, 

&ColourMatrix, Ptr, 0, "int", 0)
	return ImageAttr
}

;######################

; Function				Gdip_GetImageWidth
; Description			Gives the width of a bitmap
;
; pBitmap				Pointer to a bitmap
;
; return				Returns the width in pixels of the supplied bitmap

Gdip_GetImageWidth(pBitmap)
{
   DllCall("gdiplus\GdipGetImageWidth", A_PtrSize ? "UPtr" : "UInt", pBitmap, "uint*", Width)
   return Width
}

;######################

; Function				Gdip_GetImageHeight
; Description			Gives the height of a bitmap
;
; pBitmap				Pointer to a bitmap
;
; return				Returns the height in pixels of the supplied bitmap

Gdip_GetImageHeight(pBitmap)
{
   DllCall("gdiplus\GdipGetImageHeight", A_PtrSize ? "UPtr" : "UInt", pBitmap, "uint*", Height)
   return Height
}

;######################

Gdip_DisposeImageAttributes(ImageAttr)
{
	return DllCall("gdiplus\GdipDisposeImageAttributes", A_PtrSize ? "UPtr" : "UInt", ImageAttr)
}

;######################


For me as a newbie it is frustrating to fail due to "little" problems in projects in which the entire concept and even complex functions are working perfectly...
just me
Posts: 7224
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Single-image ico to png, but under XP

21 Nov 2015, 03:43

The current test build provides a new function LoadPicture() which (afaik) loads icon files as 32-bit bitmaps. You could try

Code: Select all

; #####################################################################################
                                                                                 ;#####
SingleImageIco2Png(Filename, sOutput)                                            ;#####
{                                                                                ;#####
   hBitmap := LoadPicture(FileName)                                              ;#####
   pBitmap := Gdip_CreateBitmapFromHBITMAP(hBitmap)                              ;#####
   Gdip_SaveBitmapToFile(pBitmap, sOutput)                                       ;#####
   Gdip_DisposeImage(pBitmap)                                                    ;#####
   DllCall("DeleteObject", "Ptr", hBitmap)                                       ;#####
}                                                                                ;#####
                                                                                 ;#####
; #####################################################################################
and see if it works on XP.
Zvonko
Posts: 210
Joined: 19 Jun 2015, 11:52

Re: Single-image ico to png, but under XP

21 Nov 2015, 04:34

Current test build 1.1.22.07.27:
https://autohotkey.com/download/1.1/Aut ... 15a1ce.zip
File not found ...

The LoadPicture() function is not included in the current normal version 1.1.22.09?
For me as a newbie it is frustrating to fail due to "little" problems in projects in which the entire concept and even complex functions are working perfectly...
just me
Posts: 7224
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Single-image ico to png, but under XP

21 Nov 2015, 05:08

The download link seems to be broken. And no, it's not included in the current release.
just me
Posts: 7224
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Single-image ico to png, but under XP

21 Nov 2015, 05:51

Well, instead of LoadPicture() you might try if this function works on Win XP. I cannot test it here.

Code: Select all

LoadICO(IcoFile, IconIndex := 1) {
   Static SizeOfHeader := 6
   Static SizeOfDirEntry := 16
   Static SHCreateMemStream := 0
   If (SHCreateMemStream = 0) {
      HMOD := DllCall("LoadLibrary", "Str", "Shlwapi.dll", "UPtr")
      If (DllCall("GetVersion", "UChar") < 6) ; Win XP
         SHCreateMemStream := DllCall("GetProcAddress", "Ptr", HMOD, "Ptr", 12, "UPtr")
      Else
         SHCreateMemStream := DllCall("GetProcAddress", "Ptr", HMOD, "AStr", "SHCreateMemStream", "UPtr")
   }
   If (SubStr(IcoFile, InStr(IcoFile, ".", False, 0)) = ".ico") && (File := FileOpen(IcoFile, "r")) {
      If File.RawRead(Header, SizeOfHeader)
      && (NumGet(Header, 0, "Short") = 0) ; must be 0
      && (NumGet(Header, 2, "Short") = 1) ; must be 1
      && (IconCount := NumGet(Header, 4, "Short")) {
         If IconIndex Between 1 And IconCount
         {
            File.Pos := SizeOfHeader + (SizeOfDirEntry * (IconIndex - 1))
            , File.RawRead(DirEntry, SizeOfDirEntry)
            , Length := NumGet(DirEntry, 8, "UInt")
            , Offset := NumGet(DirEntry, 12, "UInt")
            , BufLen := SizeOfHeader + SizeOfDirEntry + Length
            , VarSetCapacity(Buffer, BufLen, 0)
            , Addr := &Buffer
            , NumPut(1, Header, 4, "Short")
            , DllCall("RtlMoveMemory", "Ptr", Addr, "Ptr", &Header, "Ptr", SizeOfHeader)
            , Addr += SizeOfHeader
            , NumPut(SizeOfHeader + SizeOfDirEntry, DirEntry, 12, "UInt")
            , DllCall("RtlMoveMemory", "Ptr", Addr, "Ptr", &DirEntry, "Ptr", SizeOfDirEntry)
            , Addr += SizeOfDirEntry
            , File.Pos := Offset
            , File.RawRead(Addr + 0, Length)
            , IStream := DllCall(SHCreateMemStream, "Ptr", &Buffer, "UInt", BufLen, "UPtr")
            , DllCall("Gdiplus.dll\GdipCreateBitmapFromStream", "Ptr", IStream, "PtrP", pBitmap)
            , ObjRelease(IStream)
            , File.Close()
            Return pBitmap
         }
      }
      File.Close()
   }
   Return False
}
Zvonko
Posts: 210
Joined: 19 Jun 2015, 11:52

Re: Single-image ico to png, but under XP

21 Nov 2015, 06:25

In the meantime I found the test build AutoHotkey112207_27_g615a1ce.zip here:
http://www.ahkscript.info/download/1.1/

My first test (using AutoHotkey112207_27_g615a1ce_w.exe) shows that with LoadPicture() the transparency is lost (!) even on newer Windows versions! (ATM I am using Win 8.1.)

Below my test code:

Code: Select all

#NoEnv
SendMode Input  
SetWorkingDir %A_ScriptDir% 
SetBatchLines, -1

; #Warn


pToken := Gdip_Startup()


Gui Info: -dpiscale
Gui Info: Add, Text, y25, This script demonstrates how a png file can be created
Gui Info: Add, Text, yp+18, from a single-image ico file.
Gui Info: Add, Text, yp+48, Press F6 to select a file.
Gui Info: Show, x20 y20 w400 h150

RETURN


F6::
FileSelectFile, IcoF, , %A_ScriptDir%\*.*, Select a single-image ico file
   If ErrorLevel
      return
SplitPath, IcoF, , , ,IName
PngF := A_ScriptDir . "\" IName . ".png"

SingleImageIco2Png(IcoF, PngF)

ShowGui(PngF)

Gdip_Shutdown(pToken)
return



ShowGui(IcoF)		
{
global
   Gui, Destroy

   Loop, Files, %A_WinDir%\Web\Wallpaper\*.jpg, FR
	{
   	BkgPic := A_LoopFileLongPath
   	Break
	}

;BkgPic = %A_ScriptDir%\BackGImage.jpg

   Gui, -dpiscale
   Gui, Margin, 0, 0
   Gui, Color, Navy		
   Gui, Add, Picture, w800 h800 vBkg, %BkgPic%

   Gui, Add, Picture, x30 y30 w32 h32 AltSubmit BackGroundTrans, %PngF%
   Gui, Add, Picture, x110 y30 w48 h48 AltSubmit BackGroundTrans, %PngF%
   Gui, Add, Picture, x215 y30 w64 h64 AltSubmit BackGroundTrans, %PngF%
   Gui, Add, Picture, x345 y30 w128 h128 AltSubmit BackGroundTrans, %PngF%
   Gui, Add, Picture, x525 y30 w256 h256 AltSubmit BackGroundTrans, %PngF%
   Gui, Font, cWhite s12
   Gui, Add, Text, x30 y300, png-file: %PngF%
   Gui, Show, x100 y100, IcoPicture
}


InfoGuiClose:
Gdip_Shutdown(pToken)
ExitApp


; ####################################################################################
										;#####
SingleImageIco2Png(Filename, sOutput)						;#####
{										;#####
   hBitmap := LoadPicture(FileName)                                             ;#####
   pBitmap := Gdip_CreateBitmapFromHBITMAP(hBitmap)                             ;#####         
   Gdip_SaveBitmapToFile(pBitmap, sOutput)					;#####
   Gdip_DisposeImage(pBitmap)							;#####
   DllCall("DeleteObject", "Ptr", hBitmap)                                      ;#####
}										;#####
										;#####
; ####################################################################################




;######################

Gdip_Startup()
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	if !DllCall("GetModuleHandle", "str", "gdiplus", Ptr)
		DllCall("LoadLibrary", "str", "gdiplus")
	VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
	DllCall("gdiplus\GdiplusStartup", A_PtrSize ? "UPtr*" : "uint*", pToken, Ptr, &si, Ptr, 0)
	return pToken
}


Gdip_Shutdown(pToken)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	DllCall("gdiplus\GdiplusShutdown", Ptr, pToken)
	if hModule := DllCall("GetModuleHandle", "str", "gdiplus", Ptr)
		DllCall("FreeLibrary", Ptr, hModule)
	return 0
}

;######################


;#####################################################################################

Gdip_CreateBitmapFromHBITMAP(hBitmap, Palette=0)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	DllCall("gdiplus\GdipCreateBitmapFromHBITMAP", Ptr, hBitmap, Ptr, Palette, A_PtrSize ? "UPtr*" : "uint*", pBitmap)
	return pBitmap
}

;#####################################################################################


Gdip_SaveBitmapToFile(pBitmap, sOutput, Quality=75)
{
	Ptr := A_PtrSize ? "UPtr" : "UInt"
	
	SplitPath, sOutput,,, Extension
	if Extension not in BMP,DIB,RLE,JPG,JPEG,JPE,JFIF,GIF,TIF,TIFF,PNG
		return -1
	Extension := "." Extension

	DllCall("gdiplus\GdipGetImageEncodersSize", "uint*", nCount, "uint*", nSize)
	VarSetCapacity(ci, nSize)
	DllCall("gdiplus\GdipGetImageEncoders", "uint", nCount, "uint", nSize, Ptr, &ci)
	if !(nCount && nSize)
		return -2
	
	If (A_IsUnicode){
		StrGet_Name := "StrGet"
		Loop, %nCount%
		{
			sString := %StrGet_Name%(NumGet(ci, (idx := (48+7*A_PtrSize)*(A_Index-1))+32+3*A_PtrSize), "UTF-16")
			if !InStr(sString, "*" Extension)
				continue
			
			pCodec := &ci+idx
			break
		}
	} else {
		Loop, %nCount%
		{
			Location := NumGet(ci, 76*(A_Index-1)+44)
			nSize := DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "uint", 0, "int",  0, "uint", 0, "uint", 0)
			VarSetCapacity(sString, nSize)
			DllCall("WideCharToMultiByte", "uint", 0, "uint", 0, "uint", Location, "int", -1, "str", sString, "int", nSize, "uint", 0, "uint", 0)
			if !InStr(sString, "*" Extension)
				continue
			
			pCodec := &ci+76*(A_Index-1)
			break
		}
	}
	
	if !pCodec
		return -3

	if (Quality != 75)
	{
		Quality := (Quality < 0) ? 0 : (Quality > 100) ? 100 : Quality
		if Extension in .JPG,.JPEG,.JPE,.JFIF
		{
			DllCall("gdiplus\GdipGetEncoderParameterListSize", Ptr, pBitmap, Ptr, pCodec, "uint*", nSize)
			VarSetCapacity(EncoderParameters, nSize, 0)
			DllCall("gdiplus\GdipGetEncoderParameterList", Ptr, pBitmap, Ptr, pCodec, "uint", nSize, Ptr, &EncoderParameters)
			Loop, % NumGet(EncoderParameters, "UInt")      ;%
			{
				elem := (24+(A_PtrSize ? A_PtrSize : 4))*(A_Index-1) + 4 + (pad := A_PtrSize = 8 ? 4 : 0)
				if (NumGet(EncoderParameters, elem+16, "UInt") = 1) && (NumGet(EncoderParameters, elem+20, "UInt") = 6)
				{
					p := elem+&EncoderParameters-pad-4
					NumPut(Quality, NumGet(NumPut(4, NumPut(1, p+0)+20, "UInt")), "UInt")
					break
				}
			}      
		}
	}

	if (!A_IsUnicode)
	{
		nSize := DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sOutput, "int", -1, Ptr, 0, "int", 0)
		VarSetCapacity(wOutput, nSize*2)
		DllCall("MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sOutput, "int", -1, Ptr, &wOutput, "int", nSize)
		VarSetCapacity(wOutput, -1)
		if !VarSetCapacity(wOutput)
			return -4
		E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, Ptr, &wOutput, Ptr, pCodec, "uint", p ? p : 0)
	}
	else
		E := DllCall("gdiplus\GdipSaveImageToFile", Ptr, pBitmap, Ptr, &sOutput, Ptr, pCodec, "uint", p ? p : 0)
	return E ? -5 : 0
}

;######################

Gdip_DisposeImage(pBitmap)
{
   return DllCall("gdiplus\GdipDisposeImage", A_PtrSize ? "UPtr" : "UInt", pBitmap)
}
Last edited by Zvonko on 21 Nov 2015, 06:52, edited 1 time in total.
For me as a newbie it is frustrating to fail due to "little" problems in projects in which the entire concept and even complex functions are working perfectly...
Zvonko
Posts: 210
Joined: 19 Jun 2015, 11:52

Re: Single-image ico to png, but under XP

21 Nov 2015, 06:50

Just me:
LoadICO() is working perfectly on newer Windows versions, like the code with Gdip functions only, but unfortunately not on Win XP (i.e. only icon images up to 48 px are converted)...
For me as a newbie it is frustrating to fail due to "little" problems in projects in which the entire concept and even complex functions are working perfectly...
lexikos
Posts: 7057
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: Single-image ico to png, but under XP

21 Nov 2015, 18:09

LoadPicture preserves the transparency. GdipCreateBitmapFromHBITMAP does not.

GdipCreateBitmapFromScan0 might work better. tic's Gdip_CreateBitmapFromFile uses it.

N.B. ahkscript.info points at the old server. I've fixed the (latest) test release download.
just me
Posts: 7224
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Single-image ico to png, but under XP

22 Nov 2015, 03:15

Hi Zvonko!
lexikos wrote:GdipCreateBitmapFromScan0 might work better. tic's Gdip_CreateBitmapFromFile uses it.
lexikos wrote:Gdip_CreateBitmapFromFile() could easily support .ico files if you change if ext in exe,dll to if ext in exe,dll,ico. I've already used it by renaming an .ico file to .exe.

You could also add icl, cpl and scr (which are all executable files).

viewtopic.php?p=52746#p52746
You might try it. Maybe you have to specify the IconSize.
Zvonko
Posts: 210
Joined: 19 Jun 2015, 11:52

Re: Single-image ico to png, but under XP

22 Nov 2015, 08:46

Just me:
Gdip_CreateBitmapFromFile() is used already in my original code (OP)!!! And this code is working perfectly on newer Windows versions.

So we have already a perfect solution for newer Windows versions. My problem is a solution for XP!

The new function LoadPicture() is no option at all, because it requires the use of Gdip_CreateBitmapFromHBITMAP():
hBitmap := LoadPicture(FileName)
pBitmap := Gdip_CreateBitmapFromHBITMAP(hBitmap)

And Gdip_CreateBitmapFromHBITMAP() cannot be used because it is exactly the reason why the transparency is lost!

If this résumé is correct, the conclusion of the discussion is:
So far there is no solution for converting single-image ico files to png files on Windows XP.

My dearest gurus, please disprove that!
For me as a newbie it is frustrating to fail due to "little" problems in projects in which the entire concept and even complex functions are working perfectly...
just me
Posts: 7224
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Single-image ico to png, but under XP

22 Nov 2015, 08:51

Zvonko:

lexikos suggested to change Gdip_CreateBitmapFromFile() to if ext in exe,dll,ico. Did you try it?
Zvonko
Posts: 210
Joined: 19 Jun 2015, 11:52

Re: Single-image ico to png, but under XP

22 Nov 2015, 09:23

Yes, see the code in my OP:
if ext in exe,dll,ico ; !!!!!!!!!!!!!!!!!! ADDED!!!
For me as a newbie it is frustrating to fail due to "little" problems in projects in which the entire concept and even complex functions are working perfectly...
Zvonko
Posts: 210
Joined: 19 Jun 2015, 11:52

Re: Single-image ico to png, but under XP

23 Nov 2015, 03:17

So far there is no solution for converting single-image ico files (> 48 px) to png files on Windows XP (without lost of transparency).

My dearest gurus, please disprove that!
For me as a newbie it is frustrating to fail due to "little" problems in projects in which the entire concept and even complex functions are working perfectly...
just me
Posts: 7224
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Single-image ico to png, but under XP

23 Nov 2015, 03:47

Dear Zvonko!
The script below converts single-image ico files to png files without the lost of transparency.
However, the method is working only on newer Windows versions. On XP it is working only with single-image icons up to 48 px.
Are you talking about an ICO file containing exactly one icon of one size? If so, which icon sizes did you try on Win XP?

According to this article icon sizes shoudn't be restricted to a maximum of 48*48 on WIn XP. But there might be restrictions in regard to the icon format.
Zvonko
Posts: 210
Joined: 19 Jun 2015, 11:52

Re: Single-image ico to png, but under XP

23 Nov 2015, 04:34

???
Yes, a single-image ico file is an icon file containing exactly one icon of one size.
Yes, I know that Win XP cannot display icon images > 48 px.
I am not trying to display such icons on Windows XP, I am trying to convert them to png files using an AHK script on Windows XP (without lost of transparency).
I tried this with single-image icons of up to 48 px (no problem with the script from my OP),
and with single-image icons of 256 px (doesn't work).
All this work perfectly on newer Windows versions.
So far there is no solution for converting single-image ico files (> 48 px) to png files on Windows XP (without lost of transparency).

My dearest gurus, please disprove that!
For me as a newbie it is frustrating to fail due to "little" problems in projects in which the entire concept and even complex functions are working perfectly...
just me
Posts: 7224
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Single-image ico to png, but under XP

23 Nov 2015, 05:15

So you didn't try sizes between 48*48 and 256*256?

Searching in the internet I read somewhere (don't remember where) that (almost) all 256*256 icons created since Win Vista are stored using the PNG file format. It seems that Win XP isn't able to handle this format.
Interestingly, it seems to be unnecessary to convert such icons to the PNG format because the whole PNG file is stored within the ICO file. It seems to be possible to extract such icons on XP, though.
Zvonko
Posts: 210
Joined: 19 Jun 2015, 11:52

Re: Single-image ico to png, but under XP

23 Nov 2015, 05:58

Interestingly, it seems to be unnecessary to convert such icons to the PNG format because the whole PNG file is stored within the ICO file. It seems to be possible to extract such icons on XP, though.
Could you please explain these three statements more explicitely?
For me as a newbie it is frustrating to fail due to "little" problems in projects in which the entire concept and even complex functions are working perfectly...
just me
Posts: 7224
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Single-image ico to png, but under XP

23 Nov 2015, 06:19

Well, it means that it might be enough to extract the icon data from the file and write them to a file with the .PNG extension.

But you might try this version of LoadICO() as well, maybe it will work:

Code: Select all

LoadICO(IcoFile, IconIndex := 1) {
   Static SizeOfHeader := 6
   Static SizeOfDirEntry := 16
   Static SHCreateMemStream := 0
   If (SHCreateMemStream = 0) {
      HMOD := DllCall("LoadLibrary", "Str", "Shlwapi.dll", "UPtr")
      If (DllCall("GetVersion", "UChar") < 6) ; Win XP
         SHCreateMemStream := DllCall("GetProcAddress", "Ptr", HMOD, "Ptr", 12, "UPtr")
      Else
         SHCreateMemStream := DllCall("GetProcAddress", "Ptr", HMOD, "AStr", "SHCreateMemStream", "UPtr")
   }
   If (SubStr(IcoFile, InStr(IcoFile, ".", False, 0)) = ".ico") && (File := FileOpen(IcoFile, "r")) {
      If File.RawRead(Header, SizeOfHeader)
      && (NumGet(Header, 0, "Short") = 0) ; must be 0
      && (NumGet(Header, 2, "Short") = 1) ; must be 1
      && (IconCount := NumGet(Header, 4, "Short")) {
         If IconIndex Between 1 And IconCount
         {
            File.Pos := SizeOfHeader + (SizeOfDirEntry * (IconIndex - 1))
            , File.RawRead(DirEntry, SizeOfDirEntry)
            , Length := NumGet(DirEntry, 8, "UInt")
            , Offset := NumGet(DirEntry, 12, "UInt")
            , File.Pos := OffSet + 1
            , Type := Chr(File.ReadUChar())
            , Type .= Chr(File.ReadUChar())
            , Type .= Chr(File.ReadUChar())
            If (Type = "PNG") && (DllCall("GetVersion", "UChar") < 6) { ; PNG format && Win XP
               BufLen := Length
               , VarSetCapacity(Buffer, BufLen, 0)
               , File.Pos := Offset
               , File.RawRead(Buffer, Length)
            }
            Else {
               BufLen := SizeOfHeader + SizeOfDirEntry + Length
               , VarSetCapacity(Buffer, BufLen, 0)
               , Addr := &Buffer
               , NumPut(1, Header, 4, "Short")
               , DllCall("RtlMoveMemory", "Ptr", Addr, "Ptr", &Header, "Ptr", SizeOfHeader)
               , Addr += SizeOfHeader
               , NumPut(SizeOfHeader + SizeOfDirEntry, DirEntry, 12, "UInt")
               , DllCall("RtlMoveMemory", "Ptr", Addr, "Ptr", &DirEntry, "Ptr", SizeOfDirEntry)
               , Addr += SizeOfDirEntry
               , File.Pos := Offset
               , File.RawRead(Addr + 0, Length)
            }
            IStream := DllCall(SHCreateMemStream, "Ptr", &Buffer, "UInt", BufLen, "UPtr")
            , DllCall("Gdiplus.dll\GdipCreateBitmapFromStream", "Ptr", IStream, "PtrP", pBitmap)
            , ObjRelease(IStream)
            , File.Close()
            Return pBitmap
         }
      }
      File.Close()
   }
   Return False
}
Zvonko
Posts: 210
Joined: 19 Jun 2015, 11:52

Re: Single-image ico to png, but under XP

23 Nov 2015, 07:40

Thank you very much, just me, but your new version of LoadICO() doesn't solve the problem under XP.

"... because the whole PNG file is stored within the ICO file":
I don't believe this. There is only a possibility to use png in ico:
"Windows Vista added a 256×256-pixel icon view to Windows Explorer, as well as support for the compressed PNG format."
https://en.wikipedia.org/wiki/ICO_(file_format)

But at the end this is irrelevant: My single-image ico files definitely are not png.
For me as a newbie it is frustrating to fail due to "little" problems in projects in which the entire concept and even complex functions are working perfectly...
just me
Posts: 7224
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Single-image ico to png, but under XP

23 Nov 2015, 08:36

I didn't say that your ICO files are PNG, I said the whole PNG file is stored within the ICO file.

Where do you get your ICO files from? Can you upload one file?

Return to “Ask For Help”

Who is online

Users browsing this forum: malcev, mikeyww, Sabestian Caine, workworkzogzog and 46 guests