Jump to content

Calculating the Pixel Width of a single character


Recommended Posts

Hi all,

Given font size & font name, how might I find the width of a character with autoit code?

There are some example of finding string width's in this forum but I can't find a way to find the character width of a single character. For example if I want to find the width of the letter "M" at font size 700 & using the font "Gill Sans Ultra Bold", with the following VBA script we result in 981 pixel width.

'Option Explicit

'API Declares

Private Declare Function CreateDC Lib "gdi32.dll" Alias "CreateDCA" (ByVal lpDriverName As String, ByVal lpDeviceName As String, ByVal lpOutput As String, lpInitData As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32.dll" (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function CreateFontIndirect Lib "gdi32.dll" Alias "CreateFontIndirectA" (lpLogFont As LOGFONT) As Long
Private Declare Function SelectObject Lib "gdi32.dll" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function DeleteObject Lib "gdi32.dll" (ByVal hObject As Long) As Long
Private Declare Function GetTextExtentPoint32 Lib "gdi32.dll" Alias "GetTextExtentPoint32A" (ByVal hdc As Long, ByVal lpsz As String, ByVal cbString As Long, lpSize As SIZE) As Long
Private Declare Function MulDiv Lib "kernel32.dll" (ByVal nNumber As Long, ByVal nNumerator As Long, ByVal nDenominator As Long) As Long
Private Declare Function GetDC Lib "user32.dll" (ByVal hwnd As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32.dll" (ByVal hdc As Long, ByVal nIndex As Long) As Long
Private Declare Function DeleteDC Lib "gdi32.dll" (ByVal hdc As Long) As Long

Private Const LOGPIXELSY As Long = 90

Private Type LOGFONT
    lfHeight As Long
    lfWidth As Long
    lfEscapement As Long
    lfOrientation As Long
    lfWeight As Long
    lfItalic As Byte
    lfUnderline As Byte
    lfStrikeOut As Byte
    lfCharSet As Byte
    lfOutPrecision As Byte
    lfClipPrecision As Byte
    lfQuality As Byte
    lfPitchAndFamily As Byte
    lfFaceName As String * 32
End Type

Private Type SIZE
    cx As Long
    cy As Long
End Type
Public Function getLabelPixel(label As String) As Integer

  Dim font As New StdFont
  Dim sz As SIZE
  font.Name = "Gill Sans Ultra Bold"
  font.SIZE = 700

  sz = GetLabelSize(label, font)
  getLabelPixel = sz.cx

End Function

Private Function GetLabelSize(text As String, font As StdFont) As SIZE
    Dim tempDC As Long
    Dim tempBMP As Long
    Dim f As Long
    Dim lf As LOGFONT
    Dim textSize As SIZE

    ' Create a device context and a bitmap that can be used to store a
    ' temporary font object
    tempDC = CreateDC("DISPLAY", vbNullString, vbNullString, ByVal 0)
    tempBMP = CreateCompatibleBitmap(tempDC, 1, 1)

    ' Assign the bitmap to the device context
    DeleteObject SelectObject(tempDC, tempBMP)

    ' Set up the LOGFONT structure and create the font
    lf.lfFaceName = font.Name & Chr$(0)
    lf.lfHeight = -MulDiv(font.SIZE, GetDeviceCaps(GetDC(0), 90), 72) 'LOGPIXELSY
    lf.lfItalic = font.Italic
    lf.lfStrikeOut = font.StrikeThrough
    lf.lfUnderline = font.Underline
    If font.Bold Then lf.lfWeight = 800 Else lf.lfWeight = 400
    f = CreateFontIndirect(lf)

    ' Assign the font to the device context
    DeleteObject SelectObject(tempDC, f)

    ' Measure the text, and return it into the textSize SIZE structure
    GetTextExtentPoint32 tempDC, text, Len(text), textSize

    ' Clean up (very important to avoid memory leaks!)
    DeleteObject f
    DeleteObject tempBMP
    DeleteDC tempDC
  ' Return the measurements
    GetLabelSize = textSize

End Function

Sub TestMe()
    Pixels = getLabelPixel("M")
    MsgBox ("Width Pixels: " & Pixels)
    MsgBox ("Width Inches: " & (Pixels / 72))
End Sub

 

I'm not looking to create a GUI to measure the character width. I just need the width of a single given character. 🙂

Thanks

Edited by NassauSky
Clarification that I don't want to create a GUI
Link to post
Share on other sites

Try this:

#include <WinAPIGdiDC.au3>

Const $LOGPIXELSY = 90

Func getLabelPixel($label, $fontname = "Gill Sans Ultra Bold", $fontsize = 700, $italic = 0, $underline = 0, $bold = 0)
    Local $tempDC = _WinAPI_CreateCompatibleDC(0)
    Local $tempBMP = _WinAPI_CreateCompatibleBitmap($tempDC, 1, 1)
    Local $hOld1 = _WinAPI_SelectObject($tempDC, $tempBMP)
    Local $lf = DllStructCreate($tagLOGFONT)
    $lf.FaceName = $fontname
    $lf.Height = -($fontsize * _WinAPI_GetDeviceCaps($tempDC, $LOGPIXELSY) / 72)
    $lf.Italic = $italic
    $lf.Underline = $underline
    $lf.Weight = ($bold ? 800 : 400)
    Local $hFont = _WinAPI_CreateFontIndirect($lf)
    Local $hOld2 = _WinAPI_SelectObject($tempDC, $hFont)
    Local $textSize = _WinAPI_GetTextExtentPoint32($tempDC, $label)
    _WinAPI_SelectObject($tempDC, $hOld1)
    _WinAPI_SelectObject($tempDC, $hOld2)
    _WinAPI_ReleaseDC(0, $tempDC)
    _WinAPI_DeleteObject($hFont)
    _WinAPI_DeleteObject($tempBMP)
    Return $textSize
EndFunc

Global $Pixels = getLabelPixel("M")
MsgBox(0, "Test", "Width Pixels: " & $Pixels.x)

 

Edited by UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to post
Share on other sites
  • Moderators

NassauSky,

You could try my StringSize UDF - the link is in my sig. I do not have that particular font, but the width value returned seems very similar when using other fonts.

#include <MsgBoxConstants.au3>
#include "StringSize.au3"

$aRet =  _StringSize("M", 700, Default, Default, "Gill Sans Ultra Bold")

MsgBox($MB_SYSTEMMODAL, "Width", $aRet[2])

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to post
Share on other sites

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
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...