Bookmark icons are stored in an SQLite database named Favicons under user profile directory.
%LocalAppData%\Google\Chrome\User Data\Profile 1\
The icon images are stored (in png format, BLOB data type) in the "image_data" field in "favicon_bitmaps" table.
The icon images could be indexed by "icon_id" as below.
But the *.png file is stored in the database in the format of BLOB
I would like to output *.ico file directly from the BLOB data(png file) as below, without writing to hard disk and converting the format.
Database structure: https://github.com/valuex/AutohotkeyScripts/blob/main/Chrome_GetIcon.md
Blob2hBitmap(Blob_Buffer) and hBitmap2Icon(hBitmap, destIco) are from AHK forum.
But Blob2hBitmap(Blob_Buffer) is in V1.
I tried to convert it into V2, but not successful. The error message says as below.
error message snapshot: https://github.com/valuex/AutohotkeyScripts/blob/main/Chrome_GetIcon.md
Any help on fixing it would be appreciated.
Code: Select all
Stream.Release() ;Error: This value of type "Integer" has no method named "Release".
Code: Select all
#Requires AutoHotkey 2.0
#Include .\lib\Class_SQLiteDB.ahk
#Include .\lib\Gdip_All.ahk
db_file:=A_ScriptDir . "\Favicons"
DB := SQLiteDB() ; read Favicons to get bookmark icon file
DB.OpenDB(db_file)
search_result:=Get_Icon_File(1) ; blob, buffer object
pToken := Gdip_Startup()
IconName:=A_ScriptDir . "\1.ico"
PngBlob2Ico(search_result,IconName) ; directly output ico file from blob
Gdip_Shutdown(pToken )
Get_Icon_File(icon_id_number)
{
sql_cmd := 'SELECT image_data FROM favicon_bitmaps WHERE icon_id =' . icon_id_number . ' AND width = 16;'
If !DB.Query(sql_cmd, &query_result)
{
MsgBox("SQLite QUERY Error`n`nMessage: " . DB.ErrorMsg . "`nCode: " . DB.ErrorCode . "`nFile: " . db_file . "`nQuery: " . sql_cmd)
return 0
}
search_result := ''
Loop
{
result := query_result.Next(&row)
If !result
{
MsgBox("SQLite NEXT Error`n`nMessage: " . DB.ErrorMsg . "`nCode: " . DB.ErrorCode)
return 0
}
If result = -1
{
Break
}
search_result := row[1]
query_result.Free()
return search_result
}
}
PngBlob2Ico(blob,destIco)
{
hBitmap :=Blob2hBitmap(blob)
hBitmap2Icon(hBitmap, destIco)
;https://www.autohotkey.com/boards/viewtopic.php?t=124212&p=552266#p552266
Blob2hBitmap(Blob_Buffer)
{
Size := Blob_Buffer.Size
Addr := Blob_Buffer.Ptr
hBitmap := Gdip_CreateHBitmapFomData(Addr, Size)
return hBitmap
;https://www.autohotkey.com/boards/viewtopic.php?t=124212&p=552266#p552266
Gdip_CreateHBitmapFomData(DataPtr, DataSize) {
Local Bitmap := 0, HBitMap := 0
If (Bitmap := Gdip_CreateBitmapFromData(DataPtr, DataSize)) {
HBitMap := Gdip_CreateHBITMAPFromBitmap(Bitmap)
Gdip_DisposeImage(Bitmap)
}
Return HBitmap
}
Gdip_CreateBitmapFromData(DataPtr, DataSize) {
Local Bitmap := 0, Stream := 0, HR := 0
If (Stream := DllCall("Shlwapi.dll\SHCreateMemStream", "Ptr", DataPtr, "UInt", DataSize, "UPtr")) {
HR := DllCall("Gdiplus.dll\GdipCreateBitmapFromStream", "Ptr", Stream, "PtrP", Bitmap, "UInt")
Stream.Release()
}
Return (HR ? 0 : Bitmap)
}
}
; https://www.autohotkey.com/boards/viewtopic.php?style=17&t=93750&p=550636#p550523
hBitmap2Icon(hBitmap, destIco) {
; hBitmap := LoadPicture(sourcePng,"GDI+")
hIcon := HIconFromHBitmap(hBitmap)
HiconToFile(hIcon, destIco)
DllCall("DestroyIcon", "Ptr", hIcon), DllCall("DeleteObject", "Ptr", hBitmap)
HIconFromHBitmap(hBitmap) {
BITMAP := Buffer(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")
ICONINFO := Buffer(4*2 + A_PtrSize*3, 0)
NumPut("Int", 1, ICONINFO)
NumPut("Ptr", hCBM, ICONINFO, 4*2 + A_PtrSize)
NumPut("Ptr", 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
}
HiconToFile(hIcon, destFile) {
static szICONHEADER := 6, szICONDIRENTRY := 16, szBITMAP := 16 + A_PtrSize*2, szBITMAPINFOHEADER := 40
, IMAGE_BITMAP := 0, flags := (LR_COPYDELETEORG := 0x8) | (LR_CREATEDIBSECTION := 0x2000)
, szDIBSECTION := szBITMAP + szBITMAPINFOHEADER + 8 + A_PtrSize*3
, copyImageParams := ["UInt", IMAGE_BITMAP, "Int", 0, "Int", 0, "UInt", flags, "Ptr"]
ICONINFO := Buffer(8 + A_PtrSize*3, 0)
DllCall("GetIconInfo", "Ptr", hIcon, "Ptr", ICONINFO)
if !hbmMask := DllCall("CopyImage", "Ptr", NumGet(ICONINFO, 8 + A_PtrSize, "UPtr"), copyImageParams*) {
MsgBox("CopyImage failed. LastError: " . A_LastError)
Return
}
hbmColor := DllCall("CopyImage", "Ptr", NumGet(ICONINFO, 8 + A_PtrSize*2, "UPtr"), copyImageParams*)
mskDIBSECTION := Buffer(szDIBSECTION, 0)
clrDIBSECTION := Buffer(szDIBSECTION, 0)
DllCall("GetObject", "Ptr", hbmMask, "Int", szDIBSECTION, "Ptr", mskDIBSECTION)
DllCall("GetObject", "Ptr", hbmColor, "Int", szDIBSECTION, "Ptr", clrDIBSECTION)
clrWidth := NumGet(clrDIBSECTION, 4, "UInt")
clrHeight := NumGet(clrDIBSECTION, 8, "UInt")
clrBmWidthBytes := NumGet(clrDIBSECTION, 12, "UInt")
clrBmPlanes := NumGet(clrDIBSECTION, 16, "UShort")
clrBmBitsPixel := NumGet(clrDIBSECTION, 18, "UShort")
clrBits := NumGet(clrDIBSECTION, 16 + A_PtrSize, "UPtr")
colorCount := clrBmBitsPixel >= 8 ? 0 : 1 << (clrBmBitsPixel * clrBmPlanes)
clrDataSize := clrBmWidthBytes * clrHeight
mskHeight := NumGet(mskDIBSECTION, 8, "UInt")
mskBmWidthBytes := NumGet(mskDIBSECTION, 12, "UInt")
mskBits := NumGet(mskDIBSECTION, 16 + A_PtrSize, "UPtr")
mskDataSize := mskBmWidthBytes * mskHeight
iconDataSize := clrDataSize + mskDataSize
dwBytesInRes := szBITMAPINFOHEADER + iconDataSize
dwImageOffset := szICONHEADER + szICONDIRENTRY
ICONHEADER := Buffer(szICONHEADER, 0)
NumPut("UShort", 1, ICONHEADER, 2)
NumPut("UShort", 1, ICONHEADER, 4)
ICONDIRENTRY := Buffer(szICONDIRENTRY, 0)
NumPut("UChar", clrWidth, ICONDIRENTRY, 0)
NumPut("UChar", clrHeight, ICONDIRENTRY, 1)
NumPut("UChar", colorCount, ICONDIRENTRY, 2)
NumPut("UShort", clrBmPlanes, ICONDIRENTRY, 4)
NumPut("UShort", clrBmBitsPixel, ICONDIRENTRY, 6)
NumPut("UInt", dwBytesInRes, ICONDIRENTRY, 8)
NumPut("UInt", dwImageOffset, ICONDIRENTRY, 12)
NumPut("UInt", clrHeight*2, clrDIBSECTION, szBITMAP + 8)
NumPut("UInt", iconDataSize, clrDIBSECTION, szBITMAP + 20)
File := FileOpen(destFile, "w", "cp0")
File.RawWrite(ICONHEADER, szICONHEADER)
File.RawWrite(ICONDIRENTRY, szICONDIRENTRY)
File.RawWrite(clrDIBSECTION.Ptr + szBITMAP, szBITMAPINFOHEADER)
File.RawWrite(clrBits + 0, clrDataSize)
File.RawWrite(mskBits + 0, mskDataSize)
File.Close()
DllCall("DeleteObject", "Ptr", hbmColor)
DllCall("DeleteObject", "Ptr", hbmMask)
}
}
}