Jump to content

GDI+ font quality versus DrawText font quality


Go to solution Solved by ioa747,

Recommended Posts

Posted

I am working on a custom DarkMode toolbar with custom toolbar button icons made from fonts such as Segoe MDL2 Assets and Segoe Fluent Icons.

In the actual project (GUIDarkTheme UDF), the toolbar button sizes scale to current DPI. For the purpose of keeping this Example simple, the sizes are static.

My goal is obviously for the toolbar button (font icon) to look as sharp and nice as possible. With DrawText, I have been back and forth between $PROOF_QUALITY and $ANTIALIASED_QUALITY with both looking quite good at various sizes.

With GDI+, I have tried all of the following:

_GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTSYSTEMDEFAULT)
_GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTSINGLEBITPERPIXELGRIDFIT)
_GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTSINGLEBITPERPIXEL)
_GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTANTIALIASGRIDFIT)
_GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTANTIALIAS)
_GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTCLEARTYPEGRIDFIT)

The GDI+ results vary, of course. But they don't seem to be quite as good as DrawText. But I am also not as familiar with GDI+ text rendering and I could be missing something.

In my Example, the first 2 toolbar buttons are created with _CreateToolbarIconFromFont() which is using GDI+. The other two buttons are using _CreateToolbarIconFromFont_DrawText() which is using DrawText.

If anybody has any suggestions to improve overall quality (whether it's GDI+ or DrawText), please let me know. I am open to either direction as long as the outcome is best.

Thanks. :)

#include <Misc.au3>
#include <WinAPIvkeysConstants.au3>
#include <WinAPITheme.au3>
#include <GuiMenu.au3>
#include <ToolbarConstants.au3>
#include <WindowsNotifsConstants.au3>
#include <FontConstants.au3>
#include <APIGdiConstants.au3>
#include <GDIPlusConstants.au3>
#include <StructureConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiImageList.au3>
#include <GuiToolbar.au3>
#include <WinAPIGdi.au3>
#include <WindowsStylesConstants.au3>

#include <GDIPlus.au3>

; Initialize System DPI awareness
DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2)

Global Const $TBCDRF_USECDCOLORS = 0x800000
Global Const $TBCDRF_NOETCHEDEFFECT = 0x100000

Global Const $tagNMTBCUSTOMDRAW = $tagNMHDR & ";dword dwDrawStage;handle hdc;" & $tagRECT & ";dword_ptr dwItemSpec;uint uItemState;lparam lItemlParam;" & _
        "ptr hbrMonoDither;ptr hbrLines;ptr hpenLines;dword clrText;dword clrMark;dword clrTextHighlight;dword clrBtnFace;dword clrBtnHighlight;dword clrHighlightHotTrack;" & _
        "long TextLeft;long TextTop;long TextRight;long TextBottom;int nStringBkMode;int nHLStringBkMode;int iListGap;"

Global $g_sFont = 'Segoe MDL2 Assets'

Global $iToolbarColor = 0x202020

; Toolbar Button IDs
Global Enum $e_idNew = 1000, $e_idOpen, $e_idSave, $e_idHelp

; Dropdown Menu IDs
Global Enum $e_idHelpOnline = 2000, $e_idHelpAbout
Global $g_h_Dropdown

_GDIPlus_Startup()

Example()

Func Example()
    ; Create GUI
    Local $hGUI = GUICreate("_CreateToolbarIconFromFont (v" & @AutoItVersion & ")", 800, 600, -1, -1, $WS_OVERLAPPEDWINDOW)
    GUISetBkColor(0x191919)
    ;Local $hToolbar = _GUICtrlToolbar_Create($hGUI, $TBSTYLE_LIST)
    Local $hToolbar = _GUICtrlToolbar_Create($hGUI, BitOR($TBSTYLE_LIST, $TBSTYLE_FLAT))
    ;Local $hToolbar = _GUICtrlToolbar_Create($hGUI)
    _WinAPI_SetWindowTheme($hToolbar, "DarkMode", "Toolbar")
    ;_WinAPI_SetWindowTheme($hToolbar, "DarkMode_DarkTheme", "Toolbar")

    _GUICtrlToolbar_SetColorScheme($hToolbar, $iToolbarColor, $iToolbarColor)
    _GUICtrlToolbar_SetStyleTransparent($hToolbar, True)

    ;Local $iWidth = 48
    ;Local $iHeight = 48
    ;Local $iFontSize = 32

    ; Set toolbar values
    Local $iBtnWidth = 30
    Local $iBtnHeight = 30
    Local $iFontSize = 15
    Local $iFontSizeDT = 24
    Local $sFont = 'Segoe MDL2 Assets'

    ; Create normal state toolbar buttons
    Local $hHBitmapBack = _CreateToolbarIconFromFont($iBtnWidth ,$iBtnHeight, $iFontSize, $sFont, 0xE105, 0xE0E0E0)
    Local $hHBitmapForward = _CreateToolbarIconFromFont($iBtnWidth ,$iBtnHeight, $iFontSize, $sFont, 0xE946, 0xE0E0E0)
    Local $hHBitmapUp = _CreateToolbarIconFromFont_DrawText($iBtnWidth ,$iBtnHeight, $iFontSizeDT, $sFont, 0xE105, 0xE0E0E0)
    Local $hHBitmapHelp = _CreateToolbarIconFromFont_DrawText($iBtnWidth ,$iBtnHeight, $iFontSizeDT, $sFont, 0xE946, 0xE0E0E0)

    ; Create disabled state toolbar buttons
    ; previous 0xE74C
    Local $hHBitmapBackDis = _CreateToolbarIconFromFont($iBtnWidth ,$iBtnHeight, $iFontSize, $sFont, 0xE105, 0x494949)
    Local $hHBitmapForwardDis = _CreateToolbarIconFromFont($iBtnWidth ,$iBtnHeight, $iFontSize, $sFont, 0xE946, 0x494949)
    Local $hHBitmapUpDis = _CreateToolbarIconFromFont_DrawText($iBtnWidth ,$iBtnHeight, $iFontSizeDT, $sFont, 0xE105, 0x494949)
    Local $hHBitmapHelpDis = _CreateToolbarIconFromFont_DrawText($iBtnWidth ,$iBtnHeight, $iFontSizeDT, $sFont, 0xE946, 0x494949)

    ; Create normal image list
    Local $hNormal = _GUIImageList_Create($iBtnWidth, $iBtnHeight, 5) ; Use a 32 bit DIB section
    _GUIImageList_Add($hNormal, $hHBitmapBack)
    _GUIImageList_Add($hNormal, $hHBitmapForward)
    _GUIImageList_Add($hNormal, $hHBitmapUp)
    _GUIImageList_Add($hNormal, $hHBitmapHelp)
    _GUICtrlToolbar_SetImageList($hToolbar, $hNormal)

    ; Create disabled image list
    Local $hDisabled = _GUIImageList_Create($iBtnWidth, $iBtnHeight, 5) ; Use a 32 bit DIB section
    _GUIImageList_Add($hDisabled, $hHBitmapBackDis)
    _GUIImageList_Add($hDisabled, $hHBitmapForwardDis)
    _GUIImageList_Add($hDisabled, $hHBitmapUpDis)
    _GUIImageList_Add($hDisabled, $hHBitmapHelpDis)
    _GUICtrlToolbar_SetDisabledImageList($hToolbar, $hDisabled)

    ; Add strings
    Local $aStrings[4]
    $aStrings[0] = _GUICtrlToolbar_AddString($hToolbar, "&GDI Plus")
    $aStrings[1] = _GUICtrlToolbar_AddString($hToolbar, "&GDI Plus")
    $aStrings[2] = _GUICtrlToolbar_AddString($hToolbar, "&DrawText")
    $aStrings[3] = _GUICtrlToolbar_AddString($hToolbar, "&DrawText ")

    ; Add buttons
    _GUICtrlToolbar_AddButton($hToolbar, $e_idNew, 0, $aStrings[0])
    _GUICtrlToolbar_AddButton($hToolbar, $e_idOpen, 1, $aStrings[1])
    _GUICtrlToolbar_AddButton($hToolbar, $e_idSave, 2, $aStrings[2])
    $g_h_Dropdown = _GUICtrlToolbar_AddButton($hToolbar, $e_idHelp, 3, $aStrings[3])

    ; Clean up HBITMAPs created from _CreateToolbarIconFromFont()
    _WinAPI_DeleteObject($hHBitmapBack)
    _WinAPI_DeleteObject($hHBitmapForward)
    _WinAPI_DeleteObject($hHBitmapUp)
    _WinAPI_DeleteObject($hHBitmapBackDis)
    _WinAPI_DeleteObject($hHBitmapForwardDis)
    _WinAPI_DeleteObject($hHBitmapUpDis)
    _WinAPI_DeleteObject($hHBitmapHelp)
    _WinAPI_DeleteObject($hHBitmapHelpDis)

    ;GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
    ;GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")

    GUISetState(@SW_SHOW)

    ; Loop until the user exits.
    Do
    Until GUIGetMsg() = $GUI_EVENT_CLOSE

    _GDIPlus_Shutdown()
EndFunc   ;==>Example

; #FUNCTION# ====================================================================================================================
; Name...........: _CreateToolbarIconFromFont
; Description....: Determines whether the specified link of the SysLink control is focused
; Syntax.........: _CreateToolbarIconFromFont($iWidth ,$iHeight, $iFontSize, $sFontName, $UNICODE, $iColor)
; Parameters.....: $iWidth    - Width of the toolbar icon
;                  $iHeight   - Height of the toolbar icon
;                  $iFontSize - Font size used for character
;                  $sFontName - Font name. Eg. 'Segoe MDL2 Assets' or 'Segoe Fluent Icons'
;                  $UNICODE   - UNICODE code for character. Eg. 0xE72B
;                  $iColor    - Color used for character. 0xRRGGBB
; Return values..: HBITMAP
; Author.........: WildByDesign (Thanks to ahmet for helping)
; Remarks........: You must use _WinAPI_DeleteObject to delete the HBITMAP after _GUICtrlToolbar_AddButton
; ===============================================================================================================================
Func _CreateToolbarIconFromFont($iWidth ,$iHeight, $iFontSize, $sFontName, $UNICODEcode, $iColor)
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth ,$iHeight , $GDIP_PXF32ARGB)
    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    ;_GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTSYSTEMDEFAULT)
    ;_GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTSINGLEBITPERPIXELGRIDFIT)
    ;_GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTSINGLEBITPERPIXEL)
    _GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTANTIALIASGRIDFIT)
    ;_GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTANTIALIAS)
    ;_GDIPlus_GraphicsSetTextRenderingHint($hGraphics, $GDIP_TEXTRENDERINGHINTCLEARTYPEGRIDFIT)
    Local $hBrush = _GDIPlus_BrushCreateSolid(0xFFFFFFFF)
    Local $hFormat = _GDIPlus_StringFormatCreate()
    Local $hFamily = _GDIPlus_FontFamilyCreate($sFontName)
    Local $hFont = _GDIPlus_FontCreate($hFamily, $iFontSize)
    Local $tLayout = _GDIPlus_RectFCreate(0, 2, $iWidth, $iHeight)
    Local $aInfo = _GDIPlus_GraphicsMeasureString($hGraphics, ChrW($UNICODEcode), $hFont, $tLayout, $hFormat)
    _GDIPlus_GraphicsDrawStringEx($hGraphics, ChrW($UNICODEcode), $hFont, $tLayout, $hFormat, $hBrush)

    Local $hIcon = _GDIPlus_HICONCreateFromBitmap($hBitmap)
    _GDIPlus_GraphicsDispose($hGraphics)
    Local $hHBitmap = _WinAPI_Create32BitHBITMAP($hIcon, True)
    _WinAPI_DestroyIcon($hIcon)
    _GDIPlus_BitmapDispose($hBitmap)

    Return $hHBitmap
EndFunc   ;==>_CreateToolbarIconFromFont

; #FUNCTION# ====================================================================================================================
; Name...........: _CreateToolbarIconFromFont_DrawText
; Description....: Determines whether the specified link of the SysLink control is focused
; Syntax.........: _CreateToolbarIconFromFont($iWidth ,$iHeight, $iFontSize, $sFontName, $UNICODE, $iColor)
; Parameters.....: $iWidth    - Width of the toolbar icon
;                  $iHeight   - Height of the toolbar icon
;                  $iFontSize - Font size used for character
;                  $sFontName - Font name. Eg. 'Segoe MDL2 Assets' or 'Segoe Fluent Icons'
;                  $UNICODE   - UNICODE code for character. Eg. 0xE72B
;                  $iColor    - Color used for character. 0xRRGGBB
; Return values..: HBITMAP
; Author.........: WildByDesign (Thanks to ahmet for helping)
; Remarks........: You must use _WinAPI_DeleteObject to delete the HBITMAP after _GUICtrlToolbar_AddButton
; ===============================================================================================================================
Func _CreateToolbarIconFromFont_DrawText($iWidth ,$iHeight, $iFontSize, $sFontName, $UNICODEcode, $iColor)
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth ,$iHeight , $GDIP_PXF32ARGB)
    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    Local $hDC = _GDIPlus_GraphicsGetDC($hGraphics)
    Local $hFont = _WinAPI_CreateFont($iFontSize, 0, 0, 0, 400, False, False, False, $DEFAULT_CHARSET, _
        $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $PROOF_QUALITY, 0, $sFontName)
        ; also try $ANTIALIASED_QUALITY
    Local $hOldFont = _WinAPI_SelectObject($hDC, $hFont)
    _WinAPI_SetTextColor($hDC, _WinAPI_SwitchColor($iColor))
    _WinAPI_SetBkMode($hDC, $TRANSPARENT)
    Local $tRECT = _WinAPI_CreateRectEx(1, 0, $iWidth, $iHeight)
    Local $iTextFlags = BitOR($DT_SINGLELINE, $DT_CENTER, $DT_NOCLIP, $DT_VCENTER)
    _WinAPI_DrawText($hDC, ChrW($UNICODEcode), $tRECT, $iTextFlags)
    _GDIPlus_GraphicsReleaseDC($hGraphics, $hDC)
    _WinAPI_SelectObject($hDC, $hOldFont)
    _WinAPI_DeleteObject($hFont)
    Local $hIcon = _GDIPlus_HICONCreateFromBitmap($hBitmap)
    _GDIPlus_GraphicsDispose($hGraphics)
    Local $hHBitmap = _WinAPI_Create32BitHBITMAP($hIcon, True)
    _WinAPI_DestroyIcon($hIcon)
    _GDIPlus_BitmapDispose($hBitmap)

    Return $hHBitmap
EndFunc   ;==>_CreateToolbarIconFromFont_DrawText

 

Posted

I should mention that, while the DrawText looks quite nice in dark mode, it ended up looking terrible in light mode. It showed much more artifacts in light mode. So that is why I am now trying to experiment with GDI+ instead to see if I can obtain a better quality for both dark mode and light mode and at various font sizes.

  • Solution
Posted

 

Func _CreateToolbarIconFromFont($iWidth, $iHeight, $iFontSize, $sFontName, $UNICODEcode, $iColor)
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight, $GDIP_PXF32ARGB)
    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    ; Settings for Sharpening
    _GDIPlus_GraphicsSetPixelOffsetMode($hGraphics, 4)   ; HighQuality (Half-pixel offset)
    _GDIPlus_GraphicsSetTextRenderingHint($hGraphics, 5) ; $GDIP_TEXTRENDERINGHINTCLEARTYPEGRIDFIT ,

    Local $hBrush = _GDIPlus_BrushCreateSolid("0xFF" & Hex($iColor, 6))
    Local $hFormat = _GDIPlus_StringFormatCreate(BitOR(0x4000, 0x0004)) ; 0x4000 (NoClip) + 0x0004 (NoFitBlackBox)
    _GDIPlus_StringFormatSetAlign($hFormat, 1)
    _GDIPlus_StringFormatSetLineAlign($hFormat, 1)

    Local $hFamily = _GDIPlus_FontFamilyCreate($sFontName)
    Local $hFont = _GDIPlus_FontCreate($hFamily, $iFontSize)
    Local $tLayout = _GDIPlus_RectFCreate(0, 0, $iWidth, $iHeight)

    _GDIPlus_GraphicsDrawStringEx($hGraphics, ChrW($UNICODEcode), $hFont, $tLayout, $hFormat, $hBrush)

    ; Correct Cleanup
    _GDIPlus_FontDispose($hFont)
    _GDIPlus_FontFamilyDispose($hFamily)
    _GDIPlus_StringFormatDispose($hFormat)
    _GDIPlus_BrushDispose($hBrush)

    Local $hIcon = _GDIPlus_HICONCreateFromBitmap($hBitmap)
    _GDIPlus_GraphicsDispose($hGraphics)
    Local $hHBitmap = _WinAPI_Create32BitHBITMAP($hIcon, True)
    _WinAPI_DestroyIcon($hIcon)
    _GDIPlus_BitmapDispose($hBitmap)

    Return $hHBitmap
EndFunc   ;==>_CreateToolbarIconFromFont

 

I know that I know nothing

Posted

@ioa747 Thank you so much for your help. :)

Not only does it produce better results, but I also learned a lot from your solution. I had no idea how to ensure that the font character would be centered horizontally and vertically, and thanks to you I know more about _GDIPlus_StringFormatSetAlign and _GDIPlus_StringFormatSetLineAlign. I also wasn't sure how to combine the incoming $iColor with the GDI+ color which always begins with "0xFF". So that line was very helpful as well.

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