Get windows font details

Just starting out? Need help? Post your questions and find answers here.
User avatar
Michael Vogel
Addict
Addict
Posts: 2808
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Get windows font details

Post by Michael Vogel »

I'd like to see all variations (and their names for LoadFont) of one (or all) installed font(s). Some font fmilies do have different types like bold, black, semibold, light, italics, etc.

The font family 'Courier New' has 4 types (regular, italics, bold, bold+italics) which is displayed in the windows font settings.
When enumerating this font family I do get a list of around 20 entries missing also more detailed information (see code)

Code: Select all

Procedure EnumFontInfo(*elfx.ENUMLOGFONTEX,*ntmx.NEWTEXTMETRICEX,FontType.i,lParam.i)

	Debug Str(*ntmx\ntmTm\tmPitchAndFamily)+", "+Str(*ntmx\ntmTm\tmAveCharWidth)+"*"+Str(*ntmx\ntmTm\tmHeight)+", "+Str(*ntmx\ntmTm\tmWeight)+" : "+PeekS(@*elfx\elfLogFont\lfFaceName[0])
	
	ProcedureReturn #True

EndProcedure
Procedure EnumFontList(font.s)

	Protected FontLog.LOGFONT
	Protected FontHDC
	Protected Fontname.s
	
	FontHDC=GetDC_(WinID)
	FillMemory(@FontLog,SizeOf(LOGFONT))
	FontLog\lfCharSet=#DEFAULT_CHARSET
	PokeS(@FontLog\lfFaceName,font)

	If EnumFontFamiliesEx_(FontHDC,@FontLog,@EnumFontInfo(),0,0)
		ProcedureReturn #True
	Else
		ProcedureReturn #False
	EndIf

EndProcedure

;Debug EnumFontList("")
Debug EnumFontList("Courier New")
pjay
Enthusiast
Enthusiast
Posts: 253
Joined: Thu Mar 30, 2006 11:14 am

Re: Get windows font details

Post by pjay »

If I've understood your question properly, it'd be because each font can contain a number of character sets as well as the styles you mentioned:

Code: Select all

Global NewMap tm_Charset.s()
tm_Charset("0") = "ANSI_CHARSET" : tm_Charset("1") = "DEFAULT_CHARSET" : tm_Charset("2") = "SYMBOL_CHARSET"
tm_Charset("77") = "MAC_CHARSET" : tm_Charset("128") = "SHIFTJIS_CHARSET" : tm_Charset("129") = "HANGEUL_CHARSET"
tm_Charset("130") = "JOHAB_CHARSET" : tm_Charset("134") = "GB2312_CHARSET" : tm_Charset("136") = "CHINESEBIG5_CHARSET"
tm_Charset("161") = "GREEK_CHARSET" : tm_Charset("162") = "TURKISH_CHARSET"  : tm_Charset("163") = "VIETNAMESE_CHARSET" : tm_Charset("177") = "HEBREW_CHARSET" 
tm_Charset("178") = "ARABIC_CHARSET" : tm_Charset("186") = "BALTIC_CHARSET" : tm_Charset("204") = "RUSSIAN_CHARSET"
tm_Charset("222") = "THAI_CHARSET" : tm_Charset("238") = "EASTEUROPE_CHARSET" : tm_Charset("255") = "OEM_CHARSET"
Global NewMap tm_flag.s()
tm_flag("01") = "Italic " : tm_flag("11") = "Underscore " : tm_flag("21") = "Negative "
tm_flag("31") = "Outline " : tm_flag("41") = "Strikeout " : tm_flag("51") = "Bold "

Macro GetBit(num,bit) : (num >> bit) & 1 : EndMacro

Procedure EnumFontInfo(*elfx.ENUMLOGFONTEX,*ntmx.NEWTEXTMETRICEX,FontType.i,lParam.i)
  Protected myLoop, txt.s, *tmCharSet_asc.ascii = @*ntmx\ntmTm\tmCharSet : Static entries : entries + 1
  txt = Str(entries) + ": "+PeekS(@*elfx\elfLogFont\lfFaceName[0])+": " + tm_Charset(Str(*tmCharSet_asc\a)) + " "
  For myloop = 0 To 5 : txt + tm_flag(Str(myLoop)+Str(GetBit(*ntmx\ntmTm\ntmFlags,myloop))) : Next
  Debug txt
  ProcedureReturn #True
EndProcedure
Procedure EnumFontList(font.s)
  Protected FontLog.LOGFONT
	Protected FontHDC
	Protected Fontname.s
	
	FontHDC=GetDC_(WinID)
	FillMemory(@FontLog,SizeOf(LOGFONT))
	FontLog\lfCharSet=#DEFAULT_CHARSET
	PokeS(@FontLog\lfFaceName,font)

	If EnumFontFamiliesEx_(FontHDC,@FontLog,@EnumFontInfo(),0,0)
		ProcedureReturn #True
	Else
		ProcedureReturn #False
	EndIf
EndProcedure

Debug EnumFontList("Courier New")
;Debug EnumFontList("")
User avatar
charvista
Addict
Addict
Posts: 949
Joined: Tue Sep 23, 2008 11:38 pm
Location: Belgium

Re: Get windows font details

Post by charvista »

- And how to get (with Windows' API if no native code exists) the font name that can be used in LoadFont() from the filename "MyFont.ttf"?
- And how to get the total number of characters the font file contains?
- And how to get the list of characters available (not empty) available in a font?
:wink:
- Windows 11 Home 64-bit
- PureBasic 6.10 LTS (x64)
- 64 Gb RAM
- 13th Gen Intel(R) Core(TM) i9-13900K 3.00 GHz
- 5K monitor with DPI @ 200%
User avatar
Michael Vogel
Addict
Addict
Posts: 2808
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Get windows font details

Post by Michael Vogel »

I don't get any information about a font being italic or bold nor the file name needed to load this font.

Using pjays code (see below) to show details for all fonts starting with "Century751" does produce the following output here:
1: Century751 BT: ANSI_CHARSET
2: Century751 BT: TURKISH_CHARSET
3: Century751 No2 BT: ANSI_CHARSET
4: Century751 No2 BT: TURKISH_CHARSET
5: Century751 SeBd BT: ANSI_CHARSET
6: Century751 SeBd BT: TURKISH_CHARSET

The windows font settings do show 2 types for the 'BT' and 'SeBD' families (Roman and Italic) and 4 types for the 'No2 BT' font (Roman, Italic, Bold, Bold Italic).

So what will happen when using LoadFont(1,"...",24) with font names like...
... "Century751 BT"
... "Century751 BT Regular"
... "Century751 BT Roman"
... "Century751 BT Normal"
... "Century751 BT Bold"
... "Century751 BT Italic"
... "Century751 No2 BT Italic Bold"
... "Century751 No2 BT Bold Italic"

Which one will load an existing font? How do I know that "Century751 SeBd" is just a semibold variant of "Century751 BT"?
Seems more complicated than I thought :lol:

I would like to create a font requester showing only the font families and all existing types for them to choose from. Next step would be a filter to show italic or mono spaced fonts only, etc. This would keep the list smaller, otherwise you have to scroll around a while to find the font you are searching for.

Code: Select all

Global NewMap tm_Charset.s()
tm_Charset("0") = "ANSI_CHARSET" : tm_Charset("1") = "DEFAULT_CHARSET" : tm_Charset("2") = "SYMBOL_CHARSET"
tm_Charset("77") = "MAC_CHARSET" : tm_Charset("128") = "SHIFTJIS_CHARSET" : tm_Charset("129") = "HANGEUL_CHARSET"
tm_Charset("130") = "JOHAB_CHARSET" : tm_Charset("134") = "GB2312_CHARSET" : tm_Charset("136") = "CHINESEBIG5_CHARSET"
tm_Charset("161") = "GREEK_CHARSET" : tm_Charset("162") = "TURKISH_CHARSET"  : tm_Charset("163") = "VIETNAMESE_CHARSET" : tm_Charset("177") = "HEBREW_CHARSET"
tm_Charset("178") = "ARABIC_CHARSET" : tm_Charset("186") = "BALTIC_CHARSET" : tm_Charset("204") = "RUSSIAN_CHARSET"
tm_Charset("222") = "THAI_CHARSET" : tm_Charset("238") = "EASTEUROPE_CHARSET" : tm_Charset("255") = "OEM_CHARSET"
Global NewMap tm_flag.s()
tm_flag("01") = "Italic " : tm_flag("11") = "Underscore " : tm_flag("21") = "Negative "
tm_flag("31") = "Outline " : tm_flag("41") = "Strikeout " : tm_flag("51") = "Bold "

Macro GetBit(num,bit) : (num >> bit) & 1 : EndMacro

Procedure EnumFontInfo(*elfx.ENUMLOGFONTEX,*ntmx.NEWTEXTMETRICEX,FontType.i,lParam.i)

	Protected name.s
	name=PeekS(@*elfx\elfLogFont\lfFaceName[0])
	If Left(name,10)="Century751"
		Protected myLoop, txt.s, *tmCharSet_asc.ascii = @*ntmx\ntmTm\tmCharSet : Static entries : entries + 1
		txt = Str(entries) + ": "+PeekS(@*elfx\elfLogFont\lfFaceName[0])+": " + tm_Charset(Str(*tmCharSet_asc\a)) + " "
		For myloop = 0 To 5 : txt + tm_flag(Str(myLoop)+Str(GetBit(*ntmx\ntmTm\ntmFlags,myloop))) : Next
		Debug txt
	EndIf
	ProcedureReturn #True

EndProcedure
Procedure EnumFontList(font.s)
	Protected FontLog.LOGFONT
	Protected FontHDC
	Protected Fontname.s

	FontHDC=GetDC_(WinID)
	FillMemory(@FontLog,SizeOf(LOGFONT))
	FontLog\lfCharSet=#DEFAULT_CHARSET
	PokeS(@FontLog\lfFaceName,font)

	If EnumFontFamiliesEx_(FontHDC,@FontLog,@EnumFontInfo(),0,0)
		ProcedureReturn #True
	Else
		ProcedureReturn #False
	EndIf
EndProcedure

;Debug EnumFontList("Courier New")
EnumFontList("")
boddhi
Enthusiast
Enthusiast
Posts: 524
Joined: Mon Nov 15, 2010 9:53 pm

Re: Get windows font details

Post by boddhi »

I'm not at all an expert on fonts but I have worked a little on the subject (see this topic and this topic) and I will try to provide you with some details which may perhaps help you.

Independently of charsets, Windows uses 3 types of data to manage fonts: Family, subfamily and style.
The family and the style to discriminate them and the subfamily to gender the font.
In theory, the first two data are used to precisely identify the font in the event of a call and the third to allow one font to be substituted by another when it has not been found.
I say in theory because in reality this data is declared at the discretion of the foundry or the creator.

And here is the drama, everyone does a little bit of everything and anything!!!

Some use only the family to discriminate between name and style, others, more rigorously, use both types of data.
Another interesting detail that you should know is that the same font may have been taken over by another founder or creator, slightly modified in its graphic appearance and given another family name (often to add their foundry name: e.g. BT, LT, SSF, etc.) and/or another style class even though it is basically the same family...

So that sometimes for the same font, we can have a good method:
Family font name: "FamilyFontName" - Style: Normal
Family font name: "FamilyFontName" - Style: Italic
Family font name: "FamilyFontName" - Style: Bold
Family font name: "FamilyFontName" - Style: Bold Italic
        Here, Windows will group under the same name (FamilyFontName) with 4 different styles

and a shitty method:
Family font name: "FamilyFontName Normal" - Style: Normal
Family font name: "FamilyFontName Italic" - Style: Normal
Family font name: "FamilyFontName Bold" - Style: Normal
Family font name: "FamilyFontName BoldItalic" - Style: Normal
        Here, Windows will treat each font as a different font with no particular connection between them.
If my English syntax and lexicon are incorrect, please bear with Google translate and DeepL. They rarely agree with each other!
Except on this sentence...
Post Reply