Как проверить, какие наборы символов (кодовые страницы) поддерживает шрифт (имеет буквы для)?

для моего приложения мне нужно показать список системных шрифтов, но отфильтровать все шрифты, которые не поддерживают 20 предустановленных языков (набор жестко) и показать только те, которые делают.

Я могу иметь список доступных шрифтов по телефону Vcl.Forms.Screen.Fonts.
Зная только имя шрифта из этого списка, как проверить, какие наборы символов (кодовые страницы) этот шрифт поддерживает (имеет фактические буквы для) ?

например, общие шрифты, такие как Arial или Times New Roman, имеют символы для почти всех европейских языков, включая кириллицу (а также Китайский и такой). Тем не менее, многие менее распространенные шрифты часто имеют только английские буквы.

приложение предназначено для внутреннего использования, поэтому имеет функцию, которая просто запрашивает шрифт, если у него есть определенная буква, специфичная для некоторого набора символов / кодовой страницы (например,Ф или Ў или ξ) и что он не заменен буквой из другого общего шрифта (или некоторого заполнителя), было бы достаточно.

2 ответов


на GetGlyphIndices функция может использоваться для определения наличия глифа в шрифте.

цитирование документов MSDN:

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

параметры [...]

fl [in]: указывает, как должны обрабатываться глифы, если они не являются поддерживаемый. Этот параметр может иметь следующее значение.

GGI_MARK_NONEXISTING_GLYPHS -- помечает неподдерживаемые глифы шестнадцатеричным значением Значение 0xFFFF.

на Примечания разделы снова ссылаются на функции Uniscribe, например ScriptGetCMap

эта функция пытается определить представление одного глифа для каждого символа в строке, на которую указывает lpstr. Хотя это полезно для определенных целей низкого уровня( например, для управления файлами шрифтов), приложения более высокого уровня, которые хотят сопоставить строку с глиф, обычно хотят использовать Uniscribe функции.

поскольку оба API поддерживаются от Win2k и далее, это, вероятно, вопрос вкуса, который использовать.

(EDIT: только что заметил, что импорт уже находится в Windows.pas)

пример кода

procedure Test( dc : HDC);
var str : UnicodeString;
    buf : array of WORD;
    len,i : Integer;
    count : DWORD;
begin
  str := 'abc'+WideChar(16)+'äöü';
  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;

доходность

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

если вы хотите проверить всю поддержку набора символов, вы можете использовать EnumFontFamiliesEx из API Windows-это не позволяет запрашивать один шрифт, а скорее возвращает список установленных шрифтов, которые поддерживают данный набор символов (или которые имеют любой другой набор запрашиваемых функций).

вам понадобится функция обратного вызова соответствующего типа :

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;

а потом звоните как:

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;

С различными полями в TLogFont (MSDN) структура вы можете запросить широкий спектр возможностей шрифта. В этом случае я ограничил только набор символов (до китайского Big-5 в приведенном выше примере).

обратный вызов будет срабатывать один раз для каждого результирующего шрифта, возвращенного из запроса. Вам нужно будет управлять сбором этой информации по мере ее возвращения. Чтобы добавить ограничения для нескольких наборов символов, вам нужно будет вызвать EnumFontFamiliesEx один раз для каждого набора символов интереса. Следующий константы определяются в блоке RTL Windows:

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 TDictionary кажется разумным инструментом для управления этой задачей.