Jump to content

Recommended Posts

Posted (edited)

_GUIImageList_AddGlyph

a variation of  _AddFontIconToImageList   (Thanks to the @WildByDesign )

 Creates a GDI+ rendered glyph from a font and adds it to an ImageList with supersampling and rotation support.

I added some extras to try. 😍
 

; https://www.autoitscript.com/forum/topic/213857-_guiimagelist_addglyph/
;----------------------------------------------------------------------------------------
; Title...........: _GUIImageList_AddGlyph.au3
; Description.....: Creates a GDI+ rendered glyph from a font and adds it to an ImageList with supersampling and rotation support.
; AutoIt Version..: 3.3.18.0   Mod: ioa747           Script Version: 0.3
; Note............: Testet in Windows 11 Pro 25H2       Date:28/8/2026
; Modification ...: https://www.autoitscript.com/forum/topic/139260-autoit-snippets/page/29/#findComment-1554342
;----------------------------------------------------------------------------------------
;~ #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7

#include <GUIConstantsEx.au3>
#include <GuiImageList.au3>
#include <GuiListView.au3>
#include <GDIPlus.au3>
#include <WinAPITHeme.au3>

; $DPI_AWARENESS_CONTEXT_SYSTEM_AWARE = -2
DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "int_ptr", -2)

_Example()


Func _Example()
    ; Initialize GDI+
    _GDIPlus_Startup()

    Local $hGUI = GUICreate("Add Font Icons To ImageList", 600, 700)
    GUISetBkColor(0x000000)

    Local $iCSZ = 48
    Local $hImageList = _GUIImageList_Create($iCSZ, $iCSZ, 5, 1)

    Local $aDataList[16][3] = [ _ ; id, sText, $iImageIndex
            [0, "Settings|Modify application settings", _GUIImageList_AddGlyph($hImageList, "Segoe UI Emoji", 0x26A0, $iCSZ, 0xFF41B310)], _  ; "Segoe UI Emoji", .Glyph = 0x26A0 ⚠
            [0, "Home|Emoji with GlyphScale=65", _GUIImageList_AddGlyph($hImageList, "Segoe UI Emoji", 0x1F4BE, $iCSZ, 0xFF41B310, 0, 65)], _ ; "Segoe UI Emoji", .Glyph = 0x1F4BE 💾
            [0, "Save|Save current project changes", _GUIImageList_AddGlyph($hImageList, "Segoe MDL2 Assets", 0xE74E, $iCSZ, 0xFF0094FF)], _  ; "Segoe MDL2 Assets", .Glyph = 0xE74E ; Save
            [0, "1|A 90-degree rotation without flipping", _GUIImageList_AddGlyph($hImageList, "Segoe MDL2 Assets", 0xE74E, $iCSZ, 0xFF69BDF9, 1)], _
            [0, "2|A 180-degree rotation without flipping", _GUIImageList_AddGlyph($hImageList, "Segoe MDL2 Assets", 0xE74E, $iCSZ, 0xFF69BDF9, 2)], _
            [0, "3|A 270-degree rotation without flipping", _GUIImageList_AddGlyph($hImageList, "Segoe MDL2 Assets", 0xE74E, $iCSZ, 0xFF69BDF9, 3)], _
            [0, "4|No rotation and a horizontal flip", _GUIImageList_AddGlyph($hImageList, "Segoe MDL2 Assets", 0xE74E, $iCSZ, 0xFF69BDF9, 4)], _
            [0, "5|A 90-degree rotation followed by a horizontal flip", _GUIImageList_AddGlyph($hImageList, "Segoe MDL2 Assets", 0xE74E, $iCSZ, 0xFF69BDF9, 5)], _
            [0, "6|A 180-degree rotation followed by a horizontal flip", _GUIImageList_AddGlyph($hImageList, "Segoe MDL2 Assets", 0xE74E, $iCSZ, 0xFF69BDF9, 6)], _
            [0, "7|A 270-degree rotation followed by a horizontal flip", _GUIImageList_AddGlyph($hImageList, "Segoe MDL2 Assets", 0xE74E, $iCSZ, 0xFF69BDF9, 7)], _
            [0, "50|GlyphScale", _GUIImageList_AddGlyph($hImageList, "Segoe MDL2 Assets", 0xE74E, $iCSZ, 0xFFFF6A00, 0, 50)], _
            [0, "60|GlyphScale", _GUIImageList_AddGlyph($hImageList, "Segoe MDL2 Assets", 0xE74E, $iCSZ, 0xFFFF6A00, 0, 60)], _
            [0, "70|GlyphScale", _GUIImageList_AddGlyph($hImageList, "Segoe MDL2 Assets", 0xE74E, $iCSZ, 0xFFFF6A00, 0, 70)], _
            [0, "80|GlyphScale (Default)", _GUIImageList_AddGlyph($hImageList, "Segoe MDL2 Assets", 0xE74E, $iCSZ, 0xFFFF6A00, 0, 80)], _
            [0, "90|GlyphScale", _GUIImageList_AddGlyph($hImageList, "Segoe MDL2 Assets", 0xE74E, $iCSZ, 0xFFFF6A00, 0, 90)], _
            [0, "100|GlyphScale", _GUIImageList_AddGlyph($hImageList, "Segoe MDL2 Assets", 0xE74E, $iCSZ, 0xFFFF6A00, 0, 100)] _
            ]

    Local $idListView = GUICtrlCreateListView("Icon Name        |Description", 20, 20, 560, 660, BitOR($GUI_SS_DEFAULT_LISTVIEW, $LVS_NOCOLUMNHEADER))
    GUICtrlSetBkColor(-1, 0x202020)
    GUICtrlSetColor(-1, 0xFFFFFF)

    ; ImageList -> ListView
    _GUICtrlListView_SetImageList($idListView, $hImageList, 1) ; 1 = Small icon list

    Local $hLV = GUICtrlGetHandle($idListView)
    For $i = 0 To UBound($aDataList) - 1
        $aDataList[$i][0] = GUICtrlCreateListViewItem($aDataList[$i][1], $idListView)
        _GUICtrlListView_SetItemImage($hLV, $i, $aDataList[$i][2])
    Next

    ; Information: Get item rectangle
    Local $aRect = _GUICtrlListView_GetItemRect($idListview, 0)
    ConsoleWrite(StringFormat("Item Rectangle : [%d, %d, %d, %d]", $aRect[0], $aRect[1], $aRect[2], $aRect[3]) & @CRLF)


    GUISetState(@SW_SHOW)

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop
        EndSwitch
    WEnd

    ; Cleanup
    _GUIImageList_Destroy($hImageList)
    GUIDelete($hGUI)
    _GDIPlus_Shutdown()
EndFunc   ;==>_Example

; #FUNCTION# ====================================================================================================================
; Name...........: _GUIImageList_AddGlyph
; Description ...: Creates a GDI+ rendered glyph from a font and adds it to an ImageList with supersampling and rotation support.
; Syntax.........: _GUIImageList_AddGlyph($hImageList, $sFontName, $iUnicodeDecimalOrHex[, $iSize = 32[, $iARGBColor = 0xFF000000[, $iRotateFlipType = 0]]])
; Parameters ....: $hImageList             - Handle to the ImageList control.
;                  $sFontName              - Name of the font family (e.g., "Segoe MDL2 Assets", "Segoe UI Emoji").
;                  $iUnicodeDecimalOrHex   - Unicode code point (Decimal or Hex integer, e.g., 0xE74E or 0x1F60A).
;                  $iSize                  - [optional] Target icon size in pixels (Width & Height). Default is 32.
;                  $iARGBColor             - [optional] Color of the glyph in ARGB format (0xAARRGGBB). Default is 0xFF000000 (Opaque Black).
;                  $iRotateFlipType        - [optional] GDI+ RotateFlipType enumeration (0-7). Default is 0 ($GDIP_ROTATENONEFLIPNONE).
;                                                              $GDIP_RotateNoneFlipNone = 0 (Default)
;                                                              $GDIP_Rotate90FlipNone = 1
;                                                              $GDIP_Rotate180FlipNone = 2
;                                                              $GDIP_Rotate270FlipNone = 3
;                                                              $GDIP_RotateNoneFlipX = 4
;                                                              $GDIP_Rotate90FlipX = 5
;                                                              $GDIP_Rotate180FlipX = 6
;                                                              $GDIP_Rotate270FlipX = 7
;                  $iGlyphScale            - [optional] Font scale percentage relative to canvas size (1-100). Default is 80.
; Return values .: Success - The 0-based index of the added image in the ImageList.
;                  Failure - Returns index from _GUIImageList_Add or -1.
; Author ........: ioa747
; Remarks .......: Requires _GDIPlus_Startup() to be called beforehand in your script.
; ===============================================================================================================================
Func _GUIImageList_AddGlyph($hImageList, $sFontName, $iUnicodeDecimalOrHex, $iSize = 32, $iARGBColor = 0xFF000000, $iRotateFlipType = 0, $iGlyphScale = 80)
    Local $iRenderSize = $iSize * 2

    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iRenderSize, $iRenderSize)
    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    _GDIPlus_GraphicsSetSmoothingMode($hGraphics, 2)
    _GDIPlus_GraphicsSetInterpolationMode($hGraphics, $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC)
    _GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTCLEARTYPEGRIDFIT)

    Local $hBrush = _GDIPlus_BrushCreateSolid($iARGBColor)
    Local $hFamily = _GDIPlus_FontFamilyCreate($sFontName)
    Local $hFont = _GDIPlus_FontCreate($hFamily, $iRenderSize * ($iGlyphScale / 100), 0, 2)
    Local $tLayout = _GDIPlus_RectFCreate(0, 0, $iRenderSize, $iRenderSize)

    Local $hFormat = _GDIPlus_StringFormatCreate()
    _GDIPlus_StringFormatSetAlign($hFormat, 1)
    _GDIPlus_StringFormatSetLineAlign($hFormat, 1)

    ; Surrogate Pairs for Unicode > 0xFFFF (Emojis, etc.)
    Local $sChar = ""
    If $iUnicodeDecimalOrHex > 0xFFFF Then
        Local $iCode = $iUnicodeDecimalOrHex - 0x10000
        Local $iHigh = BitOR(0xD800, BitShift($iCode, 10))
        Local $iLow = BitOR(0xDC00, BitAND($iCode, 0x3FF))
        $sChar = ChrW($iHigh) & ChrW($iLow)
    Else
        $sChar = ChrW($iUnicodeDecimalOrHex)
    EndIf

    _GDIPlus_GraphicsDrawStringEx($hGraphics, $sChar, $hFont, $tLayout, $hFormat, $hBrush)

    ; Creation of final bitmap to $iSize and resampling (supersampling)
    Local $hFinalBitmap = _GDIPlus_BitmapCreateFromScan0($iSize, $iSize)
    Local $hFinalGraphics = _GDIPlus_ImageGetGraphicsContext($hFinalBitmap)
    _GDIPlus_GraphicsSetInterpolationMode($hFinalGraphics, $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC)
    _GDIPlus_GraphicsDrawImageRect($hFinalGraphics, $hBitmap, 0, 0, $iSize, $iSize)

    ; ROTATE / FLIP TRANSFORMATION
    If $iRotateFlipType Then _GDIPlus_ImageRotateFlip($hFinalBitmap, $iRotateFlipType)

    ; Conversion to Win32 HBITMAP
    Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hFinalBitmap)

    ; Addition to ImageList
    Local $iIndex = _GUIImageList_Add($hImageList, $hHBITMAP, 0)

    ; Cleanup
    _WinAPI_DeleteObject($hHBITMAP)
    _GDIPlus_StringFormatDispose($hFormat)
    _GDIPlus_FontDispose($hFont)
    _GDIPlus_FontFamilyDispose($hFamily)
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hFinalGraphics)
    _GDIPlus_BitmapDispose($hFinalBitmap)
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_BitmapDispose($hBitmap)

    Return $iIndex
EndFunc   ;==>_GUIImageList_AddGlyph

 

Please, every comment is appreciated!
leave your comments and experiences here!
Thank you very much  :)

 

Edited by ioa747
update to v0.3

I know that I know nothing

Posted

It looks like I used the wrong measurement for _GDIPlus_FontCreate in my original script.

Changing this:

Local $hFont = _GDIPlus_FontCreate($hFamily, $iRenderSize * 0.48, 0, 3)    ; 3 - A unit is 1 point or 1/72 inch

To this:

Local $hFont = _GDIPlus_FontCreate($hFamily, $iRenderSize * 0.90, 0, 2)     ; 2 - A unit is 1 pixel

This seems to be more appropriate across various DPI factors.

Posted (edited)

I added an optional  $iGlyphScale  parameter (1–100, default: 80)  to the function signature.

This allows fine-tuning the glyph size directly from the call,
which is useful not only for handling different font families,
but also for adapting to various UI themes and layouts where a custom padding or margin is required.

 

I updated the first post  with the new version.

Thank you once again   :)
for the continuous feedback and support!
 

Edited by ioa747
to GlyphScale

I know that I know nothing

Posted
5 hours ago, ioa747 said:

I added an optional  $iGlyphScale  parameter (1–100, default: 80)  to the function signature.

I really like what you've done with this function. Adding GlyphScale is an excellent idea because of how different fonts have different padding and characteristics. Your function is fantastic and is quite powerful for giving users a modern experience. This can now be used quite easily for making changes to ImageLists during WM_DPICHANGED messages to always have sharp icons/images.

The technique reminds me quite a lot of SVG since these modern fonts are also designed to scale quite well.

It opens up the possibility to have custom, modern icons for toolbar buttons, tabs and so much more. It can also be used to make nice checkboxes that some of these fonts have. The possibilities are almost endless. :)

Excellent work, as always.

Posted (edited)

following the same philosophy
to approach _GUICtrlSetGlyph
(Renders a GDI+ font glyph and assigns it directly to a GUI control)

 

because the function has all the extras flip/ rotate/ color/ size 

#include <GUIConstants.au3>
#include <GDIPlus.au3>
#include <WinAPISysWin.au3>

_Example()

Func _Example()
    _GDIPlus_Startup()

    Local $hGUI = GUICreate("GUICtrlSetGlyph Example", 400, 200)
    GUISetBkColor(0x002844)


    ; Button Control
    Local $idBtn1 = GUICtrlCreateButton(ChrW(0xE74E), 30, 40, 64, 64)
    GUICtrlSetFont ( -1, 40, 0, 0, "Segoe MDL2 Assets") ; usual way to set directly to the Button
;~  _GUICtrlSetGlyph($idBtn1, "Segoe MDL2 Assets", 0xE74E, 64, 0xFF0094FF)

    Local $idBtn2 = GUICtrlCreateButton("Save Icon", 120, 40, 64, 64)
    _GUICtrlSetGlyph($idBtn2, "Segoe MDL2 Assets", 0xE74E, 64, 0xFFFF00DC)

    Local $idBtn3 = GUICtrlCreateButton("", 210, 40, 64, 64)
    _GUICtrlSetGlyph($idBtn3, "Segoe MDL2 Assets", 0xE74E, 64, 0xFFFF6A00, 2) ; 180° Rotated



    Local $idPic1 = GUICtrlCreatePic("", 30, 120, 64, 64) ; Pic Control ??
    _GUICtrlSetGlyph($idPic1,  "Segoe MDL2 Assets", 0xE74E, 64, 0xFF41B310)

    Local $idIco1 = GUICtrlCreateIcon("shell32.dll", 7, 120, 120, 64, 64)
    _GUICtrlSetGlyph($idIco1,  "Segoe MDL2 Assets", 0xE74E, 64, 0xFFFF00DC)

    Local $idIco2 = GUICtrlCreateIcon("shell32.dll", 7, 210, 120, 64, 64)
    _GUICtrlSetGlyph($idIco2,  "Segoe MDL2 Assets", 0xE74E, 64, 0xFFFF6A00, 2) ; 180° Rotated


    GUISetState(@SW_SHOW)

    While GUIGetMsg() <> -3
    WEnd

    _GDIPlus_Shutdown()
EndFunc   ;==>_Example


; #FUNCTION# ====================================================================================================================
; Name...........: _GUICtrlSetGlyph
; Description ...: Renders a GDI+ font glyph and assigns it directly to a GUI control (Button, Pic, Icon).
; Syntax.........: _GUICtrlSetGlyph($idControl, $sFontName, $iUnicodeDecimalOrHex[, $iSize = 32[, $iARGBColor = 0xFF000000[, $iRotateFlipType = 0[, $iGlyphScale = 80]]]])
; Parameters ....: $idControl            - Control ID or HWND of the target control.
;                  $sFontName            - Name of the font family (e.g., "Segoe MDL2 Assets", "Segoe UI Emoji").
;                  $iUnicodeDecimalOrHex - Unicode code point (Decimal or Hex integer, e.g., 0xE74E or 0x1F60A).
;                  $iSize                - [optional] Icon size in pixels (Width & Height). Default is 32.
;                  $iARGBColor           - [optional] Color of the glyph in ARGB format (0xAARRGGBB). Default is 0xFF000000.
;                  $iRotateFlipType      - [optional] GDI+ RotateFlipType enumeration (0-7). Default is 0 ($GDIP_ROTATENONEFLIPNONE).
;                  $iGlyphScale          - [optional] Font scale percentage relative to canvas size (1-100). Default is 80.
; Return values .: Success - Returns the handle to the previously assigned HICON (or 0 if none).
;                  Failure - Returns 0 and sets @error.
; Author ........: ioa747
; Remarks .......: Requires _GDIPlus_Startup() to be called beforehand in your script.
; ===============================================================================================================================
Func _GUICtrlSetGlyph($idControl, $sFontName, $iUnicodeDecimalOrHex, $iSize = 32, $iARGBColor = 0xFF000000, $iRotateFlipType = 0, $iGlyphScale = 80)
    Local $hCtrl = GUICtrlGetHandle($idControl)
    If Not $hCtrl Then $hCtrl = $idControl

    Local $sClassName = _WinAPI_GetClassName($hCtrl)
    ConsoleWrite("$sClassName=" & $sClassName & @CRLF)
    Local $iMsg = 0
    Local $iStyle = _WinAPI_GetWindowLong($hCtrl, -16) ; GWL_STYLE

    Switch $sClassName
        Case "Button"
            $iMsg = $BM_SETIMAGE
            If BitAND($iStyle, 0x0040) = 0 Then
                _WinAPI_SetWindowLong($hCtrl, -16, BitOR($iStyle, 0x0040)) ; BS_ICON
            EndIf
        Case "Static"
            $iMsg = $STM_SETIMAGE
            ; Remove SS_BITMAP (0x0E) and apply SS_ICON (0x03) + SS_REALSIZECONTROL (0x40)
            $iStyle = BitAND($iStyle, BitNOT(0x0E))
            _WinAPI_SetWindowLong($hCtrl, -16, BitOR($iStyle, 0x0043))
        Case Else
            Return SetError(1, 0, 0)
    EndSwitch

    ; Supersampling Canvas Setup (2x Size for crisp AA)
    Local $iRenderSize = $iSize * 2
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iRenderSize, $iRenderSize)
    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    _GDIPlus_GraphicsSetSmoothingMode($hGraphics, 2)
    _GDIPlus_GraphicsSetInterpolationMode($hGraphics, $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC)
    _GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTCLEARTYPEGRIDFIT)

    Local $hBrush = _GDIPlus_BrushCreateSolid($iARGBColor)
    Local $hFamily = _GDIPlus_FontFamilyCreate($sFontName)
    Local $hFont = _GDIPlus_FontCreate($hFamily, $iRenderSize * ($iGlyphScale / 100), 0, 2)
    Local $tLayout = _GDIPlus_RectFCreate(0, 0, $iRenderSize, $iRenderSize)

    Local $hFormat = _GDIPlus_StringFormatCreate()
    _GDIPlus_StringFormatSetAlign($hFormat, 1)
    _GDIPlus_StringFormatSetLineAlign($hFormat, 1)

    ; Surrogate Pairs for Unicode > 0xFFFF
    Local $sChar = ""
    If $iUnicodeDecimalOrHex > 0xFFFF Then
        Local $iCode = $iUnicodeDecimalOrHex - 0x10000
        Local $iHigh = BitOR(0xD800, BitShift($iCode, 10))
        Local $iLow = BitOR(0xDC00, BitAND($iCode, 0x3FF))
        $sChar = ChrW($iHigh) & ChrW($iLow)
    Else
        $sChar = ChrW($iUnicodeDecimalOrHex)
    EndIf

    _GDIPlus_GraphicsDrawStringEx($hGraphics, $sChar, $hFont, $tLayout, $hFormat, $hBrush)

    ; Resample to Target Size
    Local $hFinalBitmap = _GDIPlus_BitmapCreateFromScan0($iSize, $iSize)
    Local $hFinalGraphics = _GDIPlus_ImageGetGraphicsContext($hFinalBitmap)
    _GDIPlus_GraphicsSetInterpolationMode($hFinalGraphics, $GDIP_INTERPOLATIONMODE_HIGHQUALITYBICUBIC)
    _GDIPlus_GraphicsDrawImageRect($hFinalGraphics, $hBitmap, 0, 0, $iSize, $iSize)

    ; Apply Rotation / Flip if needed
    If $iRotateFlipType Then _GDIPlus_ImageRotateFlip($hFinalBitmap, $iRotateFlipType)

    ; Convert to Win32 HICON (Preserves full Alpha Transparency)
    Local $hIcon = _GDIPlus_HICONCreateFromBitmap($hFinalBitmap)

    ; Send HICON message to Control ($IMAGE_ICON = 1)
    Local $hPrevIcon = _SendMessage($hCtrl, $iMsg, 1, $hIcon)

    ; Destroy previous icon if any existed to prevent memory leaks
    If $hPrevIcon Then _WinAPI_DestroyIcon($hPrevIcon)

    ; Cleanup GDI+ Resources
    _GDIPlus_StringFormatDispose($hFormat)
    _GDIPlus_FontDispose($hFont)
    _GDIPlus_FontFamilyDispose($hFamily)
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_GraphicsDispose($hFinalGraphics)
    _GDIPlus_BitmapDispose($hFinalBitmap)
    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_BitmapDispose($hBitmap)

    _WinAPI_InvalidateRect($hCtrl)

    Return $hIcon
EndFunc   ;==>_GUICtrlSetGlyph

 

Thank you once again   :)
for the continuous feedback and support!
 

Edited by ioa747

I know that I know nothing

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...