Author Topic: Icons and GDIPlus  (Read 434 times)

guga

  • Member
  • *****
  • Posts: 1346
  • Assembly is a state of art.
    • RosAsm
Icons and GDIPlus
« on: October 15, 2020, 04:01:17 AM »
Hi Guys

I already suceeded to import images in many formats using gdi+ and also grabbing their pixel data, formats etc and export to webp, png, tiff, bmp etc using Marinus and JJ´s techniques
https://masm32.com/board/index.php?topic=8483.60
http://masm32.com/board/index.php?topic=5731.30

Now...how to do the same for icons ?

The goal is:
1 - Load an icon file (including icons that have more then 1 format/size)
2 - Get their contents (pixeldata and also the transparency mask if existent)
3 - Show it on screen, and with it´s contents, place them on the proper Resources section to create the RT_ICON and related RT_GROUP_ICON structures.
4 - Export it back as icon (and whatever other formats as well)

From M$ is said that icons have fixed sizes and bpps, so only allowing formats such as:
16x16, 32x32, 48x48, 64x64, 96x96
https://docs.microsoft.com/en-us/cpp/windows/creating-an-icon-or-other-image-image-editor-for-icons?view=vs-2019

But..i already saw icons in formats such as 72x72. So is there a limitation of the icon sizes and formats ??? (i suppose, they always must remains squared, right ?)

Also, using diplus it is said to we get the HIcon to create the proper transparent background when converting it to bitmap, as in:
https://majkel.wordpress.com/2008/02/29/getting-a-gdi-bitmap-from-an-hicon-with-proper-transparency/

But...how to create the proper hcion from an ".ico" file loaded ? And what will happens if the ".ico" file contains more then 1 icon format ? Can i use LoadImageA for this purpose or i can use gdiplus to an alternate way to load and convert this ?

And also..later, once this icon isseu ios fixed or created, can this be done on the same way with cursors or cursors works completely different ?

My references to read this are:

https://www.vbforums.com/showthread.php?813055-GDI-Workaround-ICONs
http://www.jose.it-berater.org/gdiplus/reference/flatapi/bitmap/gdipcreatebitmapfromhicon.htm
https://www.autoitscript.com/autoit3/docs/libfunctions/_GDIPlus_BitmapCreateFromHICON32.htm
https://microsoft.public.win32.programmer.gdi.narkive.com/NVjTM973/loading-icons-in-gdi
https://majkel.wordpress.com/2008/02/29/getting-a-gdi-bitmap-from-an-hicon-with-proper-transparency/
https://stackoverflow.com/questions/20729156/find-out-number-of-icons-in-an-icon-resource-using-win32-api
https://social.msdn.microsoft.com/Forums/vstudio/en-US/23d7c577-e524-45d8-8969-c5fd57915fcd/reading-the-icon-file-and-its-structure?forum=vcgeneral
https://social.msdn.microsoft.com/Forums/en-US/d1fc85aa-d296-43b8-b0df-d5da7d94dcb5/the-ico-file-and-its-struct-?forum=vcgeneral
https://social.msdn.microsoft.com/Forums/vstudio/en-US/23d7c577-e524-45d8-8969-c5fd57915fcd/reading-the-icon-file-and-its-structure?forum=vcgeneral
https://docs.microsoft.com/en-us/windows/win32/menurc/icon-resource
https://docs.microsoft.com/en-us/windows/win32/menurc/cursordir
https://docs.microsoft.com/en-us/windows/win32/menurc/iconresdir
https://docs.microsoft.com/en-us/windows/win32/menurc/newheader
https://docs.microsoft.com/en-us/windows/win32/menurc/resdir
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

guga

  • Member
  • *****
  • Posts: 1346
  • Assembly is a state of art.
    • RosAsm
Re: Icons and GDIPlus
« Reply #1 on: October 15, 2020, 04:04:32 AM »
Oops...quoted on the wrong place. I quoted my own post :mrgreen: :mrgreen: :mrgreen: :mrgreen: :mrgreen:
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

guga

  • Member
  • *****
  • Posts: 1346
  • Assembly is a state of art.
    • RosAsm
Re: Icons and GDIPlus
« Reply #2 on: October 17, 2020, 04:18:52 AM »
Hi Guys

i suceeded to create the icons from the bitmap and display it on screen, but i´m having some problems using the gdiplus to do it easier.

How to convert an icon (loaded from a file) to the corresponding bitmap (and also keeping the transparency) on  way that i can also choose the actual data when the icon have multiple formats ?
And also, how to center it on the middle of a static control ? I´m using SS_CENTERIMAGE but it is not working :(

Im trying to do it in normal gdi, but using gdiplus, i could then convert the icon from whatever image format.

The icon height, for example is always the double of the normal way due to the mask, so to display i´m simply forcing height to be equal to width, like this:
Code: [Select]
...Else_If D@Message = &WM_INITDIALOG
(...)
        mov ecx D$RsrcIconNfo.IconDataPtr
        mov eax D$ecx+BITMAPINFOHEADER.biWidthDis | mov D$ecx+BITMAPINFOHEADER.biHeightDis eax ; make height of icon = width. (reset it back when exiting the dialog proc function so i can also export as an icon keeping the original values intact
        call 'FastCrt.CreatehBitmapFromBmpNfo' D$RsrcIconNfo.IconDataPtr

    ...Else_If D@Message = &WM_PAINT

        call 'user32.GetDlgItem' D@Adressee, IDC_STATIC_DISPLAYICONS ; Display it on a static control
        call On_WmPaintBmpRsrc eax, D$Rsrc_hIcon

Code: [Select]
___________________________________________________________________________________________

Proc On_WmPaintBmpRsrc:
    Arguments @Adressee, @hBitmap
    Local @hDC
    Structure @PAINTSTRUCT 64, @PAINTSTRUCT.hdcDis 0
    Uses ecx, edx

    call 'User32.BeginPaint' D@Adressee, D@PAINTSTRUCT
    mov D@hDC eax

    call BmpDrawToDC D@Adressee, eax, D@hBitmap
    call 'USER32.EndPaint' D@Adressee, D@PAINTSTRUCT

EndP
___________________________________________________________________________________________

Proc BmpDrawToDC:
    Arguments @Adressee, @hDC, @hBitmap
    Local @ctx, @hMemDC
    Structure @RECT 16, @RECT.leftDis 0, @RECT.topDis 4, @RECT.rightDis 8, @RECT.bottomDis 12
    Uses ecx, edx

    mov D@RECT.leftDis 0
    mov D@RECT.topDis 0
    mov D@RECT.rightDis 0
    mov D@RECT.bottomDis 0

    call 'GDI32.SaveDC' D@hDC | mov D@ctx eax
    call 'GDI32.CreateCompatibleDC' D@hDC | mov D@hMemDC eax
    call 'GDI32.SelectObject' D@hMemDC, D@hBitmap

    call 'User32.GetClientRect' D@Adressee, D@RECT

    call 'GDI32.BitBlt' D@hDC, 0, 0, D@RECT.rightDis, D@RECT.bottomDis, D@hMemDC, 0, 0, &SRCCOPY

    call 'GDI32.RestoreDC' D@hDC, D@ctx
    call 'GDI32.DeleteDC' D@hMemDC

EndP


« Last Edit: October 17, 2020, 10:32:46 AM by guga »
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 7642
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: Icons and GDIPlus
« Reply #3 on: October 17, 2020, 08:53:30 AM »
Hi Guga,

I use a tool called Axialis Icon Workshop and have tested creating icons that are neither square nor standard sizes and they work fine on Win10 but may not work on earlier versions. On Win10 you can make massive icons of 512 square and I think with later OS versions even larger but the size will knock you over they are so large.

Of the API functions to load icons, LoadImage is the most flexible where you can specify the size and a number of options where LoadIcon will only give you the old ones. There are of course methods of conversion but I have not seen them published. In Axialis Icon Workshop I save all of the library images as PNG so I can use them as icons, toolbar buttons and so on but that is because it handles the conversions between formats.
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

jj2007

  • Member
  • *****
  • Posts: 10676
  • Assembler is fun ;-)
    • MasmBasic
Re: Icons and GDIPlus
« Reply #4 on: October 17, 2020, 10:08:13 AM »
I know for sure that you can display an icon using GdipCreateBitmapFromStream. The problem is I have a version that works and an identical one, code-wise, that doesn't. I've been fighting with this for 2 hours now. All the paras passed are valid and identical, but one returns zero for success, the other one returns 2 for invalid parameter. Windows at its best. Will keep you posted :undecided:

guga

  • Member
  • *****
  • Posts: 1346
  • Assembly is a state of art.
    • RosAsm
Re: Icons and GDIPlus
« Reply #5 on: October 17, 2020, 10:55:48 AM »
Hi Steve.

I know about Axialis. I used to play with it  a long time ago to create or edit icons, but now all i need is understand what are the standard sizes that windows can handle on icons inside a executable file (or a dll) and how to use gdiplus to manipulate it´s pixels, convert a bmp, png etc  to icon (and vice-versa) and also keep the transparency and ability to handle the different formats inside the same icon (either a .icl or .ico).

I´m currently working on this example to give a test:
https://www.codeguru.com/cpp/w-p/win32/cursors/article.php/c4529/Creating-a-Color-Cursor-from-a-Bitmap.htm

and also will give a try on this:
https://dotnetrix.co.uk//misc.htm#tip2

So i can try to understand better how to properçly handle icons inside a executable (For RosAsm resource editor, i mean).

I did a iconeditor dll already, but it is only for 16 colors yet and it is still somewhat limited. I can´t dedicate too much time on this editor right now, because i´m fixing several issues in RosAsm resources routines 1st. My goal is to create a more decent resource compiler mixing the tools existent in Bome Restorator, Reshacker, Resource Tuner and RosAsm´s Form Wizard. (But not so soon, because it will require a lot of time to built some decent resources editor)


Hi JJ

About GdipCreateBitmapFromStream, ok... but you needed to create a hicon previously or simply loaded it as a image file ? I tried to load an icon with GdipLoadImageFromFile but it returned me the same error as yours.
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

jj2007

  • Member
  • *****
  • Posts: 10676
  • Assembler is fun ;-)
    • MasmBasic
Re: Icons and GDIPlus
« Reply #6 on: October 17, 2020, 11:42:28 AM »
simply loaded it as a image file ?

Yes, from memory via GdipCreateBitmapFromStream. And it works in the version that is 3 days older than the current :sad:

Siekmanski

  • Member
  • *****
  • Posts: 2380
Re: Icons and GDIPlus
« Reply #7 on: October 17, 2020, 11:49:55 PM »
Hi friends  :biggrin:

Here something I cooked up to load bitmaps or icons and save them as PNG icons using GdiPlus.
Hutch provided the original Icon ( wrench screwdriver )

Now we can create really small icons.  :cool:

Its written in 64bit assembly.
Creative coders use backward thinking techniques as a strategy.

jj2007

  • Member
  • *****
  • Posts: 10676
  • Assembler is fun ;-)
    • MasmBasic
Re: Icons and GDIPlus
« Reply #8 on: October 18, 2020, 09:13:48 AM »
Hi Guga,

I chased down the bug :sad:

Version 18 October works fine with icons. Try this:

GuiParas equ "Controls", w1300, h160, icon Ball, b GreenBlue   ; position, size, background
include \masm32\MasmBasic\Res\MbGui.asm
  GuiControl Canvas, "canvas"
  GetFiles \masm32\MasmBasic\icons\*.ico
Event CanvasPaint
  For_ ecx=0 To Files$(?)-1
        GuiImage Files$(ecx), ecx*34, 40.0      ; 34 pixels spacing, place in the middle
  Next
GuiEnd

guga

  • Member
  • *****
  • Posts: 1346
  • Assembly is a state of art.
    • RosAsm
Re: Icons and GDIPlus
« Reply #9 on: October 19, 2020, 11:06:57 AM »
Hi Guys, tks you.

I´m taking a look in both files. :smiley: :smiley: :smiley:

Marinus,  two doubts.

1 - How to handle multiple icons ? Does GdipCreateBitmapFromFile can be used to extract an icon containing multiple formats ?
 I saw a example using PrivateExtractIconsA Api on https://autohotkey.com/board/topic/56991-gdi-and-ico and http://forums.purebasic.com/english/viewtopic.php?f=12&t=39485&hilit=idCount but didn´t understdood it properly


2 - I ported it to 32 bits, but why you are subctracting 8 after GdipGetImagePaletteSize ? Is this value related to the size of LOGPALETTE structure ?

    lea eax D@ImagePaletteSize
    call 'gdiplus.GdipGetImagePaletteSize' D@pGdiPlusImage, eax ; Get the Color Count without loading the Palette
    mov     eax D@ImagePaletteSize
    sub     eax 8                                               ; Subtract the PaletteFlags and the PaletteCount DWORDS  <------ Size of LOGPALETTE ?
    js      @ColorCountDone
    shr     eax 2                                               ; Divide by 4 to get the Indexed Color Count
    mov     D@ImageIndexedColorCount eax
« Last Edit: October 19, 2020, 12:12:01 PM by guga »
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

Siekmanski

  • Member
  • *****
  • Posts: 2380
Re: Icons and GDIPlus
« Reply #10 on: October 19, 2020, 06:31:14 PM »
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?

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.
Creative coders use backward thinking techniques as a strategy.

guga

  • Member
  • *****
  • Posts: 1346
  • Assembly is a state of art.
    • RosAsm
Re: Icons and GDIPlus
« Reply #11 on: October 20, 2020, 03:20:52 AM »
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:

Code: [Select]
; 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
Code: [Select]

[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
Code: [Select]

; 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.

Quote
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 :)
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

Siekmanski

  • Member
  • *****
  • Posts: 2380
Re: Icons and GDIPlus
« Reply #12 on: October 20, 2020, 04:29:38 AM »
Quote
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 ?

See how to work with palettes at the GDIplusMem sources I posted earlier.
You can create a palette from an image "GdipInitializePalette" or, fill the colors in yourself, use "GdipBitmapConvertFormat" to create a Color Indexed Image.

Code: [Select]
.data
align 4
ColorPalette            dd ? ; Flag
                        dd ? ; Color count
ColorIndex              dd 256 dup (?) ; ARGB colors

.code
; save Color Indexed images with 2 to 256 colors. ( any color palette number between 2 to 256 )
align 4
SaveColorIndexedImage proc pGdiPlusImage:DWORD,pFilename:DWORD,Image_Type:DWORD,Color_Count:DWORD

    mov     ecx,Color_Count
    mov     eax,offset ColorPalette
    mov     dword ptr [eax],PaletteFlagsGrayScale
    mov     dword ptr [eax+4],ecx
    invoke  GdipInitializePalette,eax,PaletteTypeOptimal,dword ptr [eax+4],FALSE,pGdiPlusImage
    test    eax,eax
    jnz     Done

    mov     ecx,Color_Count
    mov     eax,PixelFormat8bppIndexed
    cmp     ecx,16
    ja      ConvertFormat   
    mov     eax,PixelFormat4bppIndexed
    cmp     ecx,2
    ja      ConvertFormat   
    mov     eax,PixelFormat1bppIndexed
   
ConvertFormat:
    invoke  GdipBitmapConvertFormat,pGdiPlusImage,eax,DitherTypeSolid,PaletteTypeOptimal,offset ColorPalette,0
    test    eax,eax
    jnz     Done

    invoke  MultiByteToWideChar,CP_ACP,0,pFilename,-1,offset FilenameW,MAX_PATH-1
    mov     eax,Image_Type
    mov     byte ptr[CLSID_ImageTypes],al
    invoke  GdipSaveImageToFile,pGdiPlusImage,offset FilenameW,offset CLSID_ImageTypes,NULL
Done:
    ret

SaveColorIndexedImage endp
Creative coders use backward thinking techniques as a strategy.

guga

  • Member
  • *****
  • Posts: 1346
  • Assembly is a state of art.
    • RosAsm
Re: Icons and GDIPlus
« Reply #13 on: October 20, 2020, 05:05:06 AM »
Quote
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 ?

See how to work with palettes at the GDIplusMem sources I posted earlier.
You can create a palette from an image "GdipInitializePalette" or, fill the colors in yourself, use "GdipBitmapConvertFormat" to create a Color Indexed Image.

Code: [Select]
.data
align 4
ColorPalette            dd ? ; Flag
                        dd ? ; Color count
ColorIndex              dd 256 dup (?) ; ARGB colors

.code
; save Color Indexed images with 2 to 256 colors. ( any color palette number between 2 to 256 )
align 4
SaveColorIndexedImage proc pGdiPlusImage:DWORD,pFilename:DWORD,Image_Type:DWORD,Color_Count:DWORD

    mov     ecx,Color_Count
    mov     eax,offset ColorPalette
    mov     dword ptr [eax],PaletteFlagsGrayScale
    mov     dword ptr [eax+4],ecx
    invoke  GdipInitializePalette,eax,PaletteTypeOptimal,dword ptr [eax+4],FALSE,pGdiPlusImage
    test    eax,eax
    jnz     Done

    mov     ecx,Color_Count
    mov     eax,PixelFormat8bppIndexed
    cmp     ecx,16
    ja      ConvertFormat   
    mov     eax,PixelFormat4bppIndexed
    cmp     ecx,2
    ja      ConvertFormat   
    mov     eax,PixelFormat1bppIndexed
   
ConvertFormat:
    invoke  GdipBitmapConvertFormat,pGdiPlusImage,eax,DitherTypeSolid,PaletteTypeOptimal,offset ColorPalette,0
    test    eax,eax
    jnz     Done

    invoke  MultiByteToWideChar,CP_ACP,0,pFilename,-1,offset FilenameW,MAX_PATH-1
    mov     eax,Image_Type
    mov     byte ptr[CLSID_ImageTypes],al
    invoke  GdipSaveImageToFile,pGdiPlusImage,offset FilenameW,offset CLSID_ImageTypes,NULL
Done:
    ret

SaveColorIndexedImage endp

Hmm...right, i forgot about this. You are using the COLORPALETTE structure. Many tks...i´ll adjust the code :)

[COLORPALETTE:
 COLORPALETTE.Flags: D$ 0
 COLORPALETTE.Count: D$ 0
 COLORPALETTE.Entries.ARGB: D$ 0 #256]
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

Siekmanski

  • Member
  • *****
  • Posts: 2380
Re: Icons and GDIPlus
« Reply #14 on: October 20, 2020, 05:56:48 AM »
 :thumbsup:
Creative coders use backward thinking techniques as a strategy.