Not me, but Solomon!
Don't take it so seriously, it's just a saying.
Code: Select all
SetBatchLines, -1
pngImagePath := "D:\Downloads\image.png"
destIcoPath := A_Desktop . "\test.ico"
Icons := []
PngDataFor48 := {size: 48, pack: true}
PngDataFor256 := {size: 256, pack: true}
for k, v in [16, 24, 32, PngDataFor48, PngDataFor256] {
hBitmap := ScaleImage(pngImagePath, v)
( !IsObject(v) && hIcon := HIconFromHBitmap(hBitmap) )
Icons.Push( IsObject(v) ? v : hIcon )
DllCall("DeleteObject", "Ptr", hBitmap)
}
CollectIcon(destIcoPath, Icons)
for k, v in Icons {
if !IsObject(v)
DllCall("DestroyIcon", "Ptr", v)
else {
v.PngData.SetCapacity(0)
v.PngData := ""
v := ""
}
}
ScaleImage(sourceImgFile, Data) {
static CLSID_WICImagingFactory := "{CACAF262-9370-4615-A13B-9F5539DA4C0A}"
, IID_IWICImagingFactory := "{EC5EC8A9-C395-4314-9C77-54D7A935FF70}"
, IID_IWICPixelFormatInfo := "{e8eda601-3d48-431a-ab44-69059be88bbe}"
, IID_IWICComponentInfo := "{23bc3f0a-698b-4357-886b-f24d50671334}"
, GUID_ContainerFormatPng := "{1b7cfaf4-713f-473c-bbcd-6137425faeaf}"
, GUID_WICPixelFormat32bppBGRA := "{6fddc324-4e03-4bfe-b185-3d77768dc90f}"
, GENERIC_READ := 0x80000000, WICDecodeMetadataCacheOnDemand := 0, WICBitmapEncoderNoCache := 0x00000002
, WICBitmapUseAlpha := 0, WICBitmapInterpolationModeFant := 0x3, WICBitmapInterpolationModeHighQualityCubic := 0x4
, InterpolationMode := A_OSVersion ~= "^\d" ? WICBitmapInterpolationModeHighQualityCubic : WICBitmapInterpolationModeFant
, szBITMAP := 16 + A_PtrSize*2, szBITMAPINFOHEADER := 40, szDIBSECTION := szBITMAP + szBITMAPINFOHEADER + 8 + A_PtrSize*3
, GUID, _ := VarSetCapacity(GUID, 16, 0), STATFLAG_NONAME := 0x00000001, STREAM_SEEK_SET := 0
if !IsObject(Data)
maxSize := Data
else
pack := Data.pack, maxSize := Data.size
IWICImagingFactory := ComObjCreate(CLSID_WICImagingFactory, IID_IWICImagingFactory)
Vtable( IWICImagingFactory , CreateDecoderFromFilename := 3 ).Call( "WStr", sourceImgFile, "Ptr", 0, "UInt", GENERIC_READ
, "UInt", WICDecodeMetadataCacheOnDemand, "PtrP", IWICBitmapDecoder, "UInt" )
Vtable( IWICBitmapDecoder , GetFrame := 13 ).Call( "UInt", 0, "PtrP", IWICBitmapSource )
Vtable( IWICBitmapSource , GetPixelFormat := 4 ).Call("Ptr", &GUID)
Vtable( IWICImagingFactory , CreateComponentInfo := 6 ).Call("Ptr", &GUID, "PtrP", IWICComponentInfo)
IWICPixelFormatInfo := ComObjQuery(IWICComponentInfo, IID_IWICPixelFormatInfo), ObjRelease(IWICComponentInfo)
Vtable( IWICPixelFormatInfo, GetBitsPerPixel := 13 ).Call("UIntP", bitsPerPixel)
if (bitsPerPixel != 32) {
DllCall("ole32\CLSIDFromString", "WStr", GUID_WICPixelFormat32bppBGRA, "Ptr", &GUID)
hr := DllCall("Windowscodecs\WICConvertBitmapSource", "Ptr", &GUID, "Ptr", IWICBitmapSource, "PtrP", DestIWICBitmapSource)
if (hr = 0)
ObjRelease(IWICBitmapSource), IWICBitmapSource := DestIWICBitmapSource, bitsPerPixel := 32
}
Vtable( IWICBitmapSource , GetSize := 3 ).Call("UIntP", width, "UIntP", height)
if (width > height)
height *= maxSize/width, width := maxSize
else
width *= maxSize/height, height := maxSize
width := Round(width), height := Round(height)
stride := (width*bitsPerPixel + 7)//8
size := stride*height
hBitmap := CreateDIBSection(width, -height, pBits, bitsPerPixel)
Vtable( IWICImagingFactory, CreateBitmapScaler := 11 ).Call("PtrP", IWICBitmapScaler)
Vtable( IWICBitmapScaler , Initialize := 8 ).Call("Ptr" , IWICBitmapSource, "UInt", width, "UInt", height, "UInt", InterpolationMode)
Vtable( IWICBitmapScaler , CopyPixels := 7 ).Call("Ptr", 0, "UInt", stride, "UInt", size, "Ptr", pBits)
for k, v in [IWICBitmapScaler, IWICPixelFormatInfo, IWICBitmapSource, IWICBitmapDecoder]
ObjRelease(v)
if !(width = maxSize && height = maxSize)
BitmapPadding(hBitmap, maxSize, width, height, bitsPerPixel), stride := (maxSize*bitsPerPixel + 7)//8
if pack {
VarSetCapacity(DIBSECTION, szDIBSECTION, 0)
DllCall("ole32\CLSIDFromString", "WStr", GUID_ContainerFormatPng, "Ptr", &GUID)
DllCall("GetObject", "Ptr", hBitmap, "UInt", szDIBSECTION, "Ptr", &DIBSECTION)
pBits := NumGet(DIBSECTION, 16 + A_PtrSize), imgSize := NumGet(DIBSECTION, szBITMAP + 20, "UInt")
DllCall("Ole32\CreateStreamOnHGlobal", "Ptr", 0, "UInt", true, "PtrP", IStream)
Vtable( IWICImagingFactory , CreateStream := 14 ).Call("PtrP", IWICStream)
Vtable( IWICStream , InitializeFromIStream := 14 ).Call("Ptr", IStream)
Vtable( IWICImagingFactory , CreateEncoder := 8 ).Call("Ptr", &GUID, "Ptr", 0, "PtrP", IWICBitmapEncoder)
Vtable( IWICBitmapEncoder , Initialize := 3 ).Call("Ptr", IWICStream, "UInt", WICBitmapEncoderNoCache)
Vtable( IWICBitmapEncoder , CreateNewFrame := 10 ).Call("PtrP", IWICBitmapFrameEncode, "Ptr", 0)
Vtable( IWICBitmapFrameEncode, Initialize := 3 ).Call("Ptr", 0)
Vtable( IWICBitmapFrameEncode, SetSize := 4 ).Call("UInt", maxSize, "UInt", maxSize)
DllCall("ole32\CLSIDFromString", "WStr", GUID_WICPixelFormat32bppBGRA, "Ptr", &GUID)
Vtable( IWICBitmapFrameEncode, SetPixelFormat := 6 ).Call("Ptr", &GUID)
Vtable( IWICBitmapFrameEncode, WritePixels := 10 ).Call("UInt", maxSize, "UInt", stride, "UInt", imgSize, "Ptr", pBits)
Vtable( IWICBitmapFrameEncode, Commit := 12 ).Call()
Vtable( IWICBitmapEncoder , Commit := 11 ).Call()
VarSetCapacity(STATSTG, 64 + A_PtrSize*2, 0)
Vtable( IWICStream, Stat := 12 ).Call("Ptr", &STATSTG, "UInt", STATFLAG_NONAME)
pngDataSize := NumGet(STATSTG, A_PtrSize*2, "UInt64")
Data.SetCapacity("PngData", pngDataSize)
Vtable( IWICStream, Seek := 5 ).Call("Int64", 0, "UInt", STREAM_SEEK_SET, "Ptr", 0)
Vtable( IWICStream, Read := 3 ).Call("Ptr", Data.GetAddress("PngData"), "UInt", pngDataSize, "Ptr", 0)
for k, v in [IWICBitmapFrameEncode, IWICBitmapEncoder, IStream, IWICStream]
ObjRelease(v)
Data.bitCount := bitsPerPixel
}
ObjRelease(IWICImagingFactory)
Return hBitmap
}
Vtable(ptr, n) {
Return Func("DllCall").Bind(NumGet(NumGet(ptr+0), A_PtrSize*n), "Ptr", ptr)
}
CreateDIBSection(w, h, ByRef ppvBits := 0, bpp := 32) {
hDC := DllCall("GetDC", "Ptr", 0, "Ptr")
VarSetCapacity(BITMAPINFO, 40, 0)
NumPut(40 , BITMAPINFO, 0)
NumPut( w , BITMAPINFO, 4)
NumPut( h , BITMAPINFO, 8)
NumPut( 1 , BITMAPINFO, 12)
NumPut(bpp, BITMAPINFO, 14)
hBM := DllCall("CreateDIBSection", "Ptr", hDC, "Ptr", &BITMAPINFO, "UInt", 0, "PtrP", ppvBits, "Ptr", 0, "UInt", 0, "Ptr")
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)
return hBM
}
BitmapPadding(ByRef hBitmap, maxSize, width, height, bitsPerPixel) {
hDC_New := DllCall("CreateCompatibleDC", "Ptr", 0, "Ptr")
hBM_New := CreateDIBSection(maxSize, -maxSize,, bitsPerPixel)
oBM_New := DllCall("SelectObject", "Ptr", hDC_New, "Ptr", hBM_New, "Ptr")
hDC := DllCall("CreateCompatibleDC", "Ptr", 0, "Ptr")
oBM := DllCall("SelectObject", "Ptr", hDC, "Ptr", hBitmap, "Ptr")
DllCall("BitBlt", "Ptr", hDC_New, "Int", (maxSize - width)//2, "Int", (maxSize - height)//2, "Int", width, "Int", height
, "Ptr", hDC, "Int", 0, "Int", 0, "UInt", 0x00CC0020)
DllCall("SelectObject", "Ptr", hDC, "Ptr", oBM, "Ptr")
DllCall("DeleteDC", "Ptr", hDC)
DllCall("DeleteObject", "Ptr", hBitmap)
DllCall("SelectObject", "Ptr", hDC_New, "Ptr", oBM_New, "Ptr")
DllCall("DeleteDC", "Ptr", hDC_New)
hBitmap := hBM_New
}
HIconFromHBitmap(hBitmap) {
VarSetCapacity(BITMAP, size := 4*4 + A_PtrSize*2, 0)
DllCall("GetObject", "Ptr", hBitmap, "Int", size, "Ptr", &BITMAP)
width := NumGet(BITMAP, 4, "UInt"), height := NumGet(BITMAP, 8, "UInt")
hDC := DllCall("GetDC", "Ptr", 0, "Ptr")
hCBM := DllCall("CreateCompatibleBitmap", "Ptr", hDC, "Int", width, "Int", height, "Ptr")
VarSetCapacity( ICONINFO, 4*2 + A_PtrSize*3, 0)
NumPut(1 , ICONINFO)
NumPut(hCBM , ICONINFO, 4*2 + A_PtrSize)
NumPut(hBitmap, ICONINFO, 4*2 + A_PtrSize*2)
hIcon := DllCall("CreateIconIndirect", "Ptr", &ICONINFO, "Ptr")
DllCall("DeleteObject", "Ptr", hCBM), DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)
Return hIcon
}
CollectIcon(destFile, Icons) {
static szICONHEADER := 6, szICONDIRENTRY := 16, szBITMAPINFOHEADER := 40, DIB_RGB_COLORS := 0
VarSetCapacity(ICONHEADER , szICONHEADER , 0)
VarSetCapacity(ICONDIRENTRY, szICONDIRENTRY, 0)
VarSetCapacity(ICONINFO, 8 + A_PtrSize*3, 0)
NumPut(1, ICONHEADER, 2, "UShort")
NumPut(Icons.Count(), ICONHEADER, 4, "UShort")
File := FileOpen(destFile, "w", "cp0")
File.RawWrite(ICONHEADER, szICONHEADER)
allDataSize := 0
for k, data in Icons {
if IsObject(data) {
width := height := data.size
bitCount := data.bitCount
}
else {
VarSetCapacity( clrBITMAPINFO, szBITMAPINFOHEADER, 0)
VarSetCapacity(_mskBITMAPINFO, szBITMAPINFOHEADER, 0)
VarSetCapacity( mskBITMAPINFO, szBITMAPINFOHEADER + 8, 0)
DllCall("GetIconInfo", "Ptr", data, "Ptr", &ICONINFO)
hbmMask := NumGet(ICONINFO, 8 + A_PtrSize)
hbmColor := NumGet(ICONINFO, 8 + A_PtrSize*2)
NumPut(szBITMAPINFOHEADER, clrBITMAPINFO, "UInt")
hDC := DllCall("GetDC", "Ptr", 0, "Ptr")
DllCall("GetDIBits", "Ptr", hDC, "Ptr", hbmColor, "UInt", 0, "UInt", 0, "Ptr", 0, "Ptr", &clrBITMAPINFO, "UInt", DIB_RGB_COLORS)
width := NumGet(clrBITMAPINFO, 4, "UInt")
height := NumGet(clrBITMAPINFO, 8, "UInt")
bitCount := NumGet(clrBITMAPINFO, 14, "UShort")
clrSize := NumGet(clrBITMAPINFO, 20, "UInt")
VarSetCapacity(clrBits, clrSize, 0)
NumPut(bitCount, clrBITMAPINFO, 14, "UShort")
DllCall("GetDIBits", "Ptr", hDC, "Ptr", hbmColor, "UInt", 0, "UInt", height, "Ptr", &clrBits, "Ptr", &clrBITMAPINFO, "UInt", DIB_RGB_COLORS)
NumPut(szBITMAPINFOHEADER, _mskBITMAPINFO, "UInt")
DllCall("GetDIBits", "Ptr", hDC, "Ptr", hbmMask, "UInt", 0, "UInt", 0, "Ptr", 0, "Ptr", &_mskBITMAPINFO, "UInt", DIB_RGB_COLORS)
VarSetCapacity(mskBits, clrSize, 0)
DllCall("RtlMoveMemory", "Ptr", &mskBITMAPINFO, "Ptr", &_mskBITMAPINFO, "Ptr", szBITMAPINFOHEADER)
DllCall("GetDIBits", "Ptr", hDC, "Ptr", hbmMask, "UInt", 0, "UInt", height, "Ptr", &mskBits, "Ptr", &mskBITMAPINFO, "UInt", DIB_RGB_COLORS)
DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)
DllCall("DeleteObject", "Ptr", hbmMask)
DllCall("DeleteObject", "Ptr", hbmColor)
mskSize := NumGet(mskBITMAPINFO, 20, "UInt")
iconDataSize := clrSize + mskSize
}
clrPlanes := 0
bytesInRes := IsObject(data) ? data.GetCapacity("PngData") : szBITMAPINFOHEADER + iconDataSize
offset := szICONHEADER + szICONDIRENTRY*Icons.Count() + allDataSize
allDataSize += bytesInRes
NumPut(width , ICONDIRENTRY, 0, "UChar")
NumPut(height , ICONDIRENTRY, 1, "UChar" )
NumPut(clrPlanes , ICONDIRENTRY, 4, "UShort")
NumPut(bitCount , ICONDIRENTRY, 6, "UShort")
NumPut(bytesInRes, ICONDIRENTRY, 8, "UInt")
NumPut(offset , ICONDIRENTRY, 12, "UInt")
if !IsObject(data) {
NumPut(height*2 , clrBITMAPINFO, 8, "UInt")
NumPut(0 , clrBITMAPINFO, 16, "UInt")
NumPut(iconDataSize, clrBITMAPINFO, 20, "UInt")
}
File.Pos := szICONHEADER + szICONDIRENTRY*(k - 1)
File.RawWrite(ICONDIRENTRY, szICONDIRENTRY)
File.Pos := offset
if IsObject(data)
File.RawWrite( data.GetAddress("PngData") + 0, data.GetCapacity("PngData") )
else {
File.RawWrite(clrBITMAPINFO, szBITMAPINFOHEADER)
File.RawWrite(clrBits, clrSize)
File.RawWrite(mskBits, mskSize)
}
}
File.Close()
}
Works perfectly! I added PngDataFor16, PngDataFor24, and PngDataFor32, and it created the five different size icons with the correct colors...and with a very reasonable size. For example, one 256x256 PNG that is 24,156 bytes converted into the 5-image ICO file at 36,946 bytes; another 256x256 PNG that is 72,017 bytes converted into the 5-image ICO file at 77,176 bytes. Superb! Thanks very much, Joeteadrinker wrote:Managed to pack some images to png.
Code: Select all
HIconFromHBitmap(hBitmap) {
BITMAP := Buffer(size := 4*4 + A_PtrSize*2, 0) ; V1toV2: if 'BITMAP' is a UTF-16 string, use 'VarSetStrCapacity(&BITMAP, size := 4*4 + A_PtrSize*2)'
DllCall("GetObject", "Ptr", hBitmap, "Int", size, "Ptr", BITMAP)
width := NumGet(BITMAP, 4, "UInt"), height := NumGet(BITMAP, 8, "UInt")
hDC := DllCall("GetDC", "Ptr", 0, "Ptr")
hCBM := DllCall("CreateCompatibleBitmap", "Ptr", hDC, "Int", width, "Int", height, "Ptr")
ICONINFO := Buffer(4*2 + A_PtrSize*3, 0) ; V1toV2: if 'ICONINFO' is a UTF-16 string, use 'VarSetStrCapacity(&ICONINFO, 4*2 + A_PtrSize*3)'
NumPut("UPtr", 1, ICONINFO)
NumPut(4*2 + A_PtrSize, hCBM, ICONINFO)
NumPut(4*2 + A_PtrSize*2, hBitmap, ICONINFO)
hIcon := DllCall("CreateIconIndirect", "Ptr", ICONINFO, "Ptr")
DllCall("DeleteObject", "Ptr", hCBM), DllCall("ReleaseDC", "Ptr", 0, "Ptr", hDC)
Return hIcon
}
Code: Select all
NumPut("UPtr", 1, ICONINFO)
NumPut(4*2 + A_PtrSize, hCBM, ICONINFO)
NumPut(4*2 + A_PtrSize*2, hBitmap, ICONINFO)
Code: Select all
NumPut("Int", 1, ICONINFO)
NumPut("Ptr", hCBM, ICONINFO, 4*2 + A_PtrSize)
NumPut("Ptr", hBitmap, ICONINFO, 4*2 + A_PtrSize*2)
You are welcome.
With your inspiration, I managed to sort it out - see the edit to my previous post.iPhilip wrote: ↑08 Dec 2023, 12:56The & operator creates a VarRef, which is a value representing a reference to a variable (See documentation page). In v1 the same operator passes the address of clrDIBSECTION's contents in memory. If clrDIBSECTION is a variable containing the address (I can't tell until you show more code), just omit the & operator.