ioa747 Posted August 29 Posted August 29 (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. 😍 expandcollapse popup; 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 August 30 by ioa747 update to v0.3 argumentum and WildByDesign 2 I know that I know nothing
argumentum Posted August 29 Posted August 29 200% scale ioa747 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting
WildByDesign Posted August 29 Posted August 29 53 minutes ago, argumentum said: 200% scale Try to change: Local $hFont = _GDIPlus_FontCreate($hFamily, $iRenderSize * 0.48, 0, 3) To: Local $hFont = _GDIPlus_FontCreate($hFamily, $iRenderSize * 0.32, 0, 3) It seems that we may need to apply some DPI scaling to that value somehow. argumentum 1
WildByDesign Posted August 29 Posted August 29 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. ioa747 and argumentum 2
ioa747 Posted August 30 Author Posted August 30 (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 August 30 by ioa747 to GlyphScale WildByDesign and argumentum 2 I know that I know nothing
WildByDesign Posted August 30 Posted August 30 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. ioa747 1
ioa747 Posted September 1 Author Posted September 1 (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 expandcollapse popup#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 September 1 by ioa747 WildByDesign 1 I know that I know nothing
WildByDesign Posted September 8 Posted September 8 (edited) I've spent some time trying to learn and understand how to get sharper fonts with GDI+ because apparently it can be difficult to line up perfectly on the pixel grid. And when we use fonts such as Segoe Fluent Icons or Segoe MDL2 Assets which have single pixel lines in the majority of the glyphs, you can end up with a lot of sub-pixel blur. The following puts us on the pixel grid: _GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTCLEARTYPEGRIDFIT) But from what I've read, the following can potentially take us back off the pixel grid and end up sub-pixel: _GDIPlus_StringFormatSetAlign($hFormat, 1) _GDIPlus_StringFormatSetLineAlign($hFormat, 1) Also, _GDIPlus_StringFormatCreate() can take us off the pixel grid because it adds quite a bit of horizontal padding in GDI+ which causes problems with text measurements. Instead, as a potential idea: Local $hFormat = _GDIPlus_StringFormatCreateTypographic() ; #FUNCTION# ==================================================================================================================== ; Name ..........: _GDIPlus_StringFormatCreateTypographic ; Description ...: Helper function to determine if control is native AutoIt control or UDF-created control. ; Author.........: UEZ ; Link...........: https://www.autoitscript.com/forum/topic/159683-hard-death-of-autoit-x64-with-gdiplus-call/#findComment-1158866 ; Remarks........: A generic, typographic StringFormat object has the following characteristics: ; ; - String format flags StringFormatFlagsLineLimit, StringFormatFlagsNoClip, and StringFormatFlagsNoFitBlackBox are set. ; - Character alignment and line alignment are set to StringAlignmentNear. ; - Language ID is set to neutral language, which means that the current language associated with the calling thread is used. ; - String digit substitution is set to StringDigitSubstituteUser. ; - Hot key prefix is set to HotkeyPrefixNone. ; - Number of tab stops is set to zero. ; - String trimming is set to StringTrimmingNone. ; =============================================================================================================================== Func _GDIPlus_StringFormatCreateTypographic() Local $aResult = DllCall($__g_hGDIPDll, "uint", "GdipStringFormatGetGenericTypographic", "ptr*", 0) If @error Then Return SetError(@error, @extended, 0) Return $aResult[1] EndFunc ;==>_GDIPlus_StringFormatCreateTypographic The only downside is that we would not get the automatic vertical and horizontal centering. We would have to use _GDIPlus_GraphicsMeasureString() with the included _GDIPlus_StringFormatCreateTypographic() as the hFormat to measure the string (now without extra GDI+ padding) and do the math to determine how many pixels to move the character along the pixel grid to handle the vertical and horizontal centering. Anyway, it's just an idea to slightly improve sharpness but it would involve some extra work/math in the function to center the glyph. I've tested it in a few of my functions an it works quite well. EDIT: I am still achieving much sharper glyphs (at smaller font sizes) using pure GDI with ExtTextOut, but I am having significant issues getting a transparent background which is needed for ImageLists. Solid background is sharp and great due to cleartype blending, but transparent ends up jagged. Edited September 8 by WildByDesign ioa747 and argumentum 2
ioa747 Posted September 12 Author Posted September 12 @WildByDesign Excellent approach! I adopted your idea about using typographic measurement to eliminate GDI+ padding and implemented it into a clean, reusable function: _GUIImageList_AddGlyph() expandcollapse popup; 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.5 ; 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> ; Set DPI awareness to System Aware DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext", "int_ptr", -2) ; Initialize GDI+ _GDIPlus_Startup() _Example() ; Cleanup _GDIPlus_Shutdown() Func _Example() Local $hGUI = GUICreate("Add Font Icons To ImageList", 600, 900) GUISetBkColor(0x000000) Local $iCSZ = 48 Local $hImageList = _GUIImageList_Create($iCSZ, $iCSZ, 5, 1) Local $aDataList[16][3] = [ _ ; id, sText, $iImageIndex [0, "Settings|Emoji GlyphScale=80", _GUIImageList_AddGlyph($hImageList, "Segoe UI Emoji", "⚠", $iCSZ, 0xFF41B310)], _ [0, "Home|Emoji with GlyphScale=50", _GUIImageList_AddGlyph($hImageList, "Segoe UI Emoji", "💾", $iCSZ, 0xFF41B310, 0, 50)], _ [0, "Save|Save current project changes", _GUIImageList_AddGlyph($hImageList, "Segoe MDL2 Assets", 0xE74E, $iCSZ, 0xFF0094FF)], _ [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, 860, BitOR($GUI_SS_DEFAULT_LISTVIEW, $LVS_NOCOLUMNHEADER)) GUICtrlSetBkColor(-1, 0x202020) GUICtrlSetColor(-1, 0xFFFFFF) ; Bind ImageList to ListView (1 = Small icon list) _GUICtrlListView_SetImageList($idListView, $hImageList, 1) 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 GUIDelete($hGUI) _GUIImageList_Destroy($hImageList) EndFunc ;==>_Example ; #FUNCTION# ==================================================================================================================== ; Name...........: _GUIImageList_AddGlyph ; Description ...: Creates a GDI+ rendered glyph from a font using typographic measurement and adds it directly to an ImageList. ; Syntax.........: _GUIImageList_AddGlyph($hImageList, $sFontName, $vUnicodeOrChar[, $iSize = 32[, $iARGBColor = 0xFF000000[, $iRotateFlipType = 0[, $iGlyphScale = 80]]]]) ; Parameters ....: $hImageList - Handle to the ImageList control. ; $sFontName - Name of the font family (e.g., "Segoe MDL2 Assets", "Segoe UI Emoji"). ; $vUnicodeOrChar - Unicode CodePoint Hex/Dec (e.g. 0xE74E) OR literal String for Emojis (e.g. "⚠️"). ; $iSize - [optional] Target icon size in pixels. Default is 32. ; $iARGBColor - [optional] Color of the glyph in ARGB format. Default is 0xFF000000. ; $iRotateFlipType- [optional] GDI+ RotateFlipType enumeration (0-7). Default is 0. ; $iGlyphScale - [optional] Font scale percentage (1-100). Default is 80. ; Return values .: Success - The 0-based index of the added image in the ImageList. ; Failure - Returns -1 and sets @error. ; Author ........: ioa747 ; =============================================================================================================================== Func _GUIImageList_AddGlyph($hImageList, $sFontName, $vUnicodeOrChar, $iSize = 32, $iARGBColor = 0xFF000000, $iRotateFlipType = 0, $iGlyphScale = 80) Local $sChar = "", $hFormat, $bIsEmoji = False ; Static handle for Typographic format (created only once) Static $hStaticTypographic = 0 ; Calculate scaled font size based on percentage Local $fScaledSize = $iSize * ($iGlyphScale / 100) ; 1. Check if String -> Standard Format & Full Canvas Layout (Emoji mode) If IsString($vUnicodeOrChar) Then $sChar = $vUnicodeOrChar $bIsEmoji = True $hFormat = _GDIPlus_StringFormatCreate() _GDIPlus_StringFormatSetAlign($hFormat, 1) ; Center alignment _GDIPlus_StringFormatSetLineAlign($hFormat, 1) ; Center line alignment ; 2. Check if Numeric -> Typographic Format & Custom tRect (Icon Font mode) Else If $vUnicodeOrChar > 0xFFFF Then Local $iCode = $vUnicodeOrChar - 0x10000 Local $iHigh = BitOR(0xD800, BitShift($iCode, 10)) Local $iLow = BitOR(0xDC00, BitAND($iCode, 0x3FF)) $sChar = ChrW($iHigh) & ChrW($iLow) Else $sChar = ChrW($vUnicodeOrChar) EndIf ; Acquire Generic Typographic format handle if not already cached If Not IsPtr($hStaticTypographic) Then Local $aResult = DllCall($__g_hGDIPDll, "uint", "GdipStringFormatGetGenericTypographic", "ptr*", 0) If Not @error And $aResult[1] Then $hStaticTypographic = $aResult[1] EndIf $hFormat = $hStaticTypographic EndIf ; Create 1:1 Target Bitmap canvas Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iSize, $iSize) Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap) _GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTANTIALIASGRIDFIT) Local $hBrush = _GDIPlus_BrushCreateSolid($iARGBColor) Local $hFamily = _GDIPlus_FontFamilyCreate($sFontName) Local $hFont = _GDIPlus_FontCreate($hFamily, $fScaledSize, 0, 2) Local $tLayout = _GDIPlus_RectFCreate(0, 0, $iSize, $iSize) ; Render Glyph If $bIsEmoji Then ; Emojis: Draw directly inside $tLayout _GDIPlus_GraphicsDrawStringEx($hGraphics, $sChar, $hFont, $tLayout, $hFormat, $hBrush) Else ; Icon Fonts: Measure bounds and snap to exact integer pixel grid Local $aBounds = _GDIPlus_GraphicsMeasureString($hGraphics, $sChar, $hFont, $tLayout, $hFormat) Local $fDrawWidth = DllStructGetData($aBounds[0], "Width") Local $fDrawHeight = DllStructGetData($aBounds[0], "Height") Local $iX = Floor(($iSize - $fDrawWidth) / 2) Local $iY = Floor(($iSize - $fDrawHeight) / 2) Local $tRect = _GDIPlus_RectFCreate($iX, $iY, $fDrawWidth, $fDrawHeight) _GDIPlus_GraphicsDrawStringEx($hGraphics, $sChar, $hFont, $tRect, $hFormat, $hBrush) EndIf If $iRotateFlipType Then _GDIPlus_ImageRotateFlip($hBitmap, $iRotateFlipType) Local $hHBITMAP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap) Local $aRet = DllCall("comctl32.dll", "int", "ImageList_Add", "ptr", $hImageList, "ptr", $hHBITMAP, "ptr", 0) Local $iIndex = (IsArray($aRet) And Not @error) ? $aRet[0] : -1 ; Cleanup Win32 & GDI+ Handles _WinAPI_DeleteObject($hHBITMAP) ; Dispose ONLY if it was a dynamically allocated StringFormat (Emoji mode) If $bIsEmoji And $hFormat Then _GDIPlus_StringFormatDispose($hFormat) _GDIPlus_FontDispose($hFont) _GDIPlus_FontFamilyDispose($hFamily) _GDIPlus_BrushDispose($hBrush) _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 WildByDesign 1 I know that I know nothing
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now