How to check which fonts (code pages) a font supports (are there letters for)?

For my application, I need to show a list of system fonts, but filter out all fonts that do not support 20 predefined languages ​​(the set is hard-coded) and show only those that do.

I have a list of available fonts, calling Vcl.Forms.Screen.Fonts .
Knowing only the font name from this list, how can I check which character sets (code pages) this font supports (has the actual letters for)?

For example, regular fonts, such as Arial or Times New Roman, have characters for almost all European languages, including Cyrillic (as well as Chinese and such). However, many less common fonts often have only English letters.

The application is intended for internal use, therefore, with a function that simply asks for a font if it has a specific letter specific to a certain character set / code page (e.g. or Ў or ξ ), and that it is not replaced by a letter from another generic font ( or some placeholder).

+6
source share
2 answers

The GetGlyphIndices function can be used to determine if a glyph is in the font.

MSDN docs summary:

 DWORD GetGlyphIndices( _In_ HDC hdc, _In_ LPCTSTR lpstr, _In_ int c, _Out_ LPWORD pgi, _In_ DWORD fl ); 

Options [...]

fl [in]: specifies how to handle glyphs if they are not supported. This parameter may be the following value.

GGI_MARK_NONEXISTING_GLYPHS - GGI_MARK_NONEXISTING_GLYPHS unsupported characters with a hex value of 0xffff.

The Note sections again refer to Uniscribe functions, for example. ScriptGetCMap

This function attempts to identify a representation with one glyph for each character in the string pointed to by lpstr. While this is useful for certain low-level purposes (such as managing font files), higher-level applications that want to map strings to glyphs generally want to use the Uniscribe functions.

Since both APIs are supported from Win2k onwards, this is probably a matter of taste that you can use.

(EDIT: just noticed that the import is already in Windows.pas)

Code example

 procedure Test( dc : HDC); var str : UnicodeString; buf : array of WORD; len,i : Integer; count : DWORD; begin str := 'abc'+WideChar($0416)+'Àâü'; len := Length(str); SetLength( buf, len); count := GetGlyphIndicesW( dc, PWideChar(str), len, @buf[0], GGI_MARK_NONEXISTING_GLYPHS); if count > 0 then begin for i := 0 to count-1 do begin Write('index ',i,': '); if buf[i] = $FFFF then Writeln('glyph missing') else Writeln('ok'); end; end; end; 

gives

 index 0: ok index 1: ok index 2: ok index 3: glyph missing index 4: ok index 5: ok index 6: ok 
+6
source

If you want to test support for the entire character set, you can use EnumFontFamiliesEx from the Windows API - this does not allow you to request a single font, but rather returns a list of installed fonts that support a given character set (or that have any other set of requested functions).

You will need a callback function of the appropriate type :

 function EnumFontCallback(lpelfe : PLogFont; lpntme : PNewTextMetricEX; FontType : DWORD; lp : LPARAM) : integer; stdcall; begin TMemo(lp).Lines.Add(lpelfe^.lfFaceName); result := 1; // return zero to end enumeration end; 

And then called like:

 procedure TForm1.Button1Click(Sender: TObject); var lf : TLogFont; begin ZeroMemory(@lf,SizeOf(TLogFont)); lf.lfCharSet := CHINESEBIG5_CHARSET; if not EnumFontFamiliesEx(Canvas.Handle, // HDC lf, // TLogFont @EnumFontCallback, // Callback Pointer NativeInt(Memo1), // user supplied pointer 0) then // must be zero begin // function call failed. end; end; 

Using the various fields in the TLogFont (MSDN) structure, you can request a wide range of font functions. In this case, I limited only the character set (for Chinese Big-5 in the example above).

The callback will fire once for each resulting font returned from the request. You will need to manage the collection of this information as it returns. To add restrictions to multiple character sets, you will need to call EnumFontFamiliesEx once for each character set. The following constants are defined in the Windows RTL block:

 ANSI_CHARSET BALTIC_CHARSET CHINESEBIG5_CHARSET DEFAULT_CHARSET // depends on system locale EASTEUROPE_CHARSET GB2312_CHARSET GREEK_CHARSET HANGUL_CHARSET MAC_CHARSET OEM_CHARSET // depends on OS RUSSIAN_CHARSET SHIFTJIS_CHARSET SYMBOL_CHARSET TURKISH_CHARSET VIETNAMESE_CHARSET JOHAB_CHARSET ARABIC_CHARSET HEBREW_CHARSET THAI_CHARSET 

A cross reference will then be up to you - a TDictionary seems like a reasonable tool to manage this task.

+1
source

All Articles