Как проверить, какие наборы символов (кодовые страницы) поддерживает шрифт (имеет буквы для)?
для моего приложения мне нужно показать список системных шрифтов, но отфильтровать все шрифты, которые не поддерживают 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
кажется разумным инструментом для управления этой задачей.