Hi guga,
1)
Are you pointing to old style Icons with the same image but different sizes in one?
If so, I haven't tested it.
I presume ( could be wrong ) GdiPlus loads the first icon image...
If this is the case, you could resize the image data by yourself?
Have you tried to load such an icon with GdiPlus?
Hi Marinus
Yes, i´m testing old style icons , but didn´t tested your routine on them yet. About resizing the icons, this is not desirable, because we need to know previously how many icons are there and also multiple icons can be used as a kind of icon library (.icl) ( I saw multiple icons created with different images and not necessarily with the same image resized). Of course, i can resize other types of files to create the icons, but for icons itself, iis not desirable to change their original format while the app is being disassembled. The icons routine i´m using for the disassembler purposes (and not only the assembler/resource compiler ones). So, when we dealing with old apps to be disassemble or even apps written in whatever compiler or style we can see weird things in what concerns the resources icons. That´s why i´m trying to maintain the amount of icons and their internal data on the same way as they were compiled. If the user wants to use the disassembled icons then is ok to he do it, since the contents/structures are kept intact. Otherwise, he can also delete or replace to newer ones, if needed.
To read any icon (including the ones having multiple sizes), and generating the proper RT_GROUP_ICONS i did this:
; Equtes used for displacment of the structures GRPICONDIR and GRPICONDIRENTRY
[GRPICONDIR.idReservedDis 0
GRPICONDIR.idTypeDis 2
GRPICONDIR.idCountDis 4]
[Size_Of_GRPICONDIR 6]
[GRPICONDIRENTRY.bWidthDis 0
GRPICONDIRENTRY.bHeightDis 1
GRPICONDIRENTRY.bColorCountDis 2
GRPICONDIRENTRY.bReservedDis 3
GRPICONDIRENTRY.wPlanesDis 4
GRPICONDIRENTRY.wBitCountDis 6
GRPICONDIRENTRY.dwBytesInResDis 8
GRPICONDIRENTRY.nIdDis 12]
[Size_Of_GRPICONDIRENTRY 14]
Proc ReadIconFiles:
Local @MemFile, @TmpIconMem, @TmpGrpIconMem,
@iconCount, @InternalId, @pCurIconEntry, @iconType, @GrpIconSize
Uses ecx, edx, esi, edi
mov D$OtherFilePtr 0
mov D$OtherFileLen 0
call 'FastCRT.GetOpenFileEx' D$hwnd, OtherSaveFilter, {B$ "Choose a Icon File", 0}, {B$ 'Icon Files (*.ico)', 0 '*.ico', 0 0}, &NULL, OtherFilePtr, OtherFileLen, 0, &NULL
On eax = 0, ExitP
call IsIcon D$OtherFilePtr
If eax = &FALSE
call 'USER32.MessageBoxA' D$hwnd, {B$ "Bad Icon file", 0}, {B$ "Warning", 0}, &MB_SYSTEMMODAL
call VMemFree D$OtherFilePtr | mov D$OtherFilePtr 0 | ExitP ; release the memory previously allocated inside GetOpenFileEx
xor eax eax
ExitP
End_If
mov esi D$OtherFilePtr | movzx ecx W$esi+ICONDIR.idCountDis | mov D@iconCount ecx
movzx ecx W$esi+ICONDIR.idTypeDis | mov D@iconType ecx
add esi Size_Of_ICONDIR ; Start of our Icon entries from where we will get their data
mov D@pCurIconEntry esi ; current icon entry
If D@iconType <> 1 ; <---- Redundant/Old routine. Already checked in IsIcon . I can remove this small check here. Todo once further tests (force IsIcon to exportthe pointer to CurIconEntry in eax on sucess and keep 0 in error cases)
call 'USER32.MessageBoxA' D$hwnd, {B$ "Bad Icon file", 0}, {B$ "Warning", 0}, &MB_SYSTEMMODAL
call VMemFree D$OtherFilePtr | mov D$OtherFilePtr 0 | ExitP ; release the memory previously allocated inside GetOpenFileEx
End_If
; get last Item Count (will be used as an internal Id in both RT_ICON and RT_GROUP_ICON)
mov edi D$IconList | mov eax D$edi+CustomListArray.CountDis | inc eax | mov D@InternalId eax
; We write both the RT_ICON and the RT_GROUP_ICON:
; 1st we write the Group Icon (RT_GROUP_ICON)
; The RT_GROUP_ICON is built on a single Memory Buuffer, no matter how many multiple icons it do have.
; Therefore, be carefull, when deleting it, because once you delete the main group, all the other variables
; Should be zeroed (and not deleted again or individually), because all of them are part of the same memory block
mov D@MemFile 0 | lea eax D@MemFile
mov ecx Size_Of_GRPICONDIRENTRY | imul ecx D@iconCount | add ecx Size_Of_GRPICONDIR
call VMemAlloc eax, ecx ; Allocate enough memory to the group of icons
mov D@TmpGrpIconMem eax
mov edi D$GroupIconList; | inc D$edi+CustomListArray.CountDis
mov eax D$edi+CustomListArray.CountDis | imul eax Size_Of_RosAsm_Rsrc_Data | inc D$edi+CustomListArray.CountDis
add eax CustomListArray.DataDis | add edi eax ; points to the last empty record
call CreateIconGroup D$OtherFilePtr, D@TmpGrpIconMem, D@InternalId
mov D$edi+RosAsm_Rsrc_Data.SizeDis eax | mov D@GrpIconSize eax; save the size of the resource
mov eax D@TmpGrpIconMem | mov D$edi+RosAsm_Rsrc_Data.PtrDis eax
; and point to the end of the GroupList
mov esi D$GroupIconList | mov eax D$esi+CustomListArray.CountDis | imul eax Size_Of_RosAsm_Rsrc_Data | add eax CustomListArray.DataDis
add esi eax | mov D$GroupIconListPtr esi
; 2nd create the Icon Data (RT_ICON including the multiformat)
mov edi D$IconList | mov eax D$edi+CustomListArray.CountDis | mov ecx D@iconCount | add D$edi+CustomListArray.CountDis ecx
imul eax Size_Of_RosAsm_Rsrc_Data | add eax CustomListArray.DataDis | add edi eax
.Do
mov D@MemFile 0 | lea eax D@MemFile
; We could recalculate the correct size of the Bitmap inside the icon , but let´s use the full size and later we fix it
call VMemAlloc eax, D$OtherFileLen
mov D$edi+RosAsm_Rsrc_Data.PtrDis eax | mov D@TmpIconMem eax
mov eax D@InternalId | mov D$edi+RosAsm_Rsrc_Data.IdDis eax
; get the size of the icon entry and copy it to our output
mov esi D@pCurIconEntry | mov eax D$esi+ICONDIRENTRY.dwBytesInResDis | mov ecx D$esi+ICONDIRENTRY.dwImageOffsetDis
mov D$edi+RosAsm_Rsrc_Data.SizeDis eax | add D@pCurIconEntry Size_Of_ICONDIRENTRY
; Now do the same for the icon data
add ecx D$OtherFilePtr
call 'RosMem.FastMemcpy' D@TmpIconMem, ecx, eax
add edi Size_Of_RosAsm_Rsrc_Data
inc D@InternalId
dec D@iconCount
.Loop_Until D@iconCount = 0
mov eax D$IconList | mov ecx D$eax+CustomListArray.CountDis | add eax CustomListArray.DataDis
call 'FastCRT.qsort' eax, ecx, Size_Of_RosAsm_Rsrc_Data, StartRsrcSort ; sort the icons
mov B$OnIconLoad &TRUE
mov eax D$GroupIconList | dec D$eax+CustomListArray.CountDis
call AskForResID eax, D@TmpGrpIconMem, D@GrpIconSize ; <---- Simpley ask the user for the desired ID he wants his icon contains
mov B$OnIconLoad &FALSE
mov eax D$GroupIconList | mov ecx D$eax+CustomListArray.CountDis | add eax CustomListArray.DataDis
call 'FastCRT.qsort' eax, ecx, Size_Of_RosAsm_Rsrc_Data, StartRsrcSort ; sort the icons groups
; finally release the allocated data
call 'RosMem.VMemFree' D$OtherFilePtr | mov D$OtherFilePtr 0
EndP
; Make sure we are dealing with icon files
[Size_Of_BITMAPV2INFOHEADER 52]
[Size_Of_BITMAPV3INFOHEADER 56]
[Size_Of_BITMAPV4INFOHEADER 108]
[Size_Of_BITMAPV5INFOHEADER 124]
Proc IsIcon:
Arguments @pFile
Local @iCount
Uses esi
mov esi D@pFile
movzx eax W$esi+ICONDIR.idCountDis | mov D@iCount eax
.If W$esi+ICONDIR.idTypeDis <> 1
xor eax eax
.Else
add esi Size_Of_ICONDIR
.Do
mov eax D$esi+ICONDIRENTRY.dwImageOffsetDis | add eax D@pFile
If_Or D$eax+BITMAPINFOHEADER.biSizeDis = Size_Of_BITMAPINFOHEADER, D$eax+BITMAPINFOHEADER.biSizeDis = Size_Of_BITMAPV2INFOHEADER,
D$eax+BITMAPINFOHEADER.biSizeDis = Size_Of_BITMAPV3INFOHEADER, D$eax+BITMAPINFOHEADER.biSizeDis = Size_Of_BITMAPV4INFOHEADER,
D$eax+BITMAPINFOHEADER.biSizeDis = Size_Of_BITMAPV5INFOHEADER
Else
xor eax eax
ExitP
End_If
add esi Size_Of_ICONDIRENTRY
dec D@iCount
.Loop_Until D@iCount = 0
mov eax &TRUE
.End_If
EndP
; create the group of icons inside the rsrc section
; Eax return the total size of thefilled resource
Proc CreateIconGroup:
Arguments @Input, @Output, @IdStart
Local @InternalId, @iconCount, @Return
Uses esi, edi
mov esi D@Input
movzx eax W$esi+ICONDIR.idCountDis | mov D@iconCount eax
imul eax Size_Of_GRPICONDIRENTRY | add eax Size_Of_GRPICONDIR | mov D@Return eax
mov edi D@Output
mov eax D$esi+ICONDIR.idReservedDis | mov D$edi+GRPICONDIR.idReservedDis eax
mov ax W$esi+ICONDIR.idCountDis | mov W$edi+GRPICONDIR.idCountDis ax
add esi Size_Of_ICONDIR
add edi Size_Of_GRPICONDIR
mov eax D@IdStart | mov D@InternalId eax
; at esi we have the start of our Icon data (ICONDIRENTRY)
.Do
; copy all bytes from bWidth to bReserved
mov eax D$esi+ICONDIRENTRY.bWidthDis | mov D$edi+GRPICONDIRENTRY.bWidthDis eax
; copy all Words from wPlanes to wBitCount
mov eax D$esi+ICONDIRENTRY.wPlanesDis | mov D$edi+GRPICONDIRENTRY.wPlanesDis eax
mov eax D$esi+ICONDIRENTRY.dwBytesInResDis | mov D$edi+GRPICONDIRENTRY.dwBytesInResDis eax
mov eax D@InternalId | mov W$edi+GRPICONDIRENTRY.nIdDis ax ; we can açlso have a maximum of 65535 icons in the resource section
add esi Size_Of_ICONDIRENTRY
add edi Size_Of_GRPICONDIRENTRY
inc D@InternalId
dec D@iconCount
.Loop_Until D@iconCount = 0
mov eax D@Return
EndP
See ? A bit overhead to load multiple icons. That´s why i was thinking if there is an easier and shorter way to do it in gdiplus.
2)
No, there are 2 dwords in front of the color palette. (PaletteFlags and PaletteCount)
I subtract them from the palette size to get the color count.
Now I can calculate the color count without loading the color palette first to memory and read the PaletteCount dword.
It also deals with images without a color palette.
OK, but...where i can find the PaletteFlags and PaletteCount, i couldn´t find it in your code. Are they generated internally in gdiplus ? (as a poart of a structure or something ?). If so, which api are creating them ?
I´ll try using your png routine to create icons from png (and later whatever other image formats, such as bmp, jpg, webp, tiff etc onto .ico) and later put the proper warning messages in case of teh generated image is not in the standard or maximum formats (squared 256x256, for example) allowing the user to resize it accordlying.
Then i can read JJ´s function to see what else can be used/improved too :)