我知道如何用几行XAML创建一个WPF字体选择器,绑定到Fonts.SystemFontFamilies(感谢Norris Cheng的优秀博客文章),但我无法弄清楚如何过滤掉所有国际和其他非罗马字母字体家庭.我的用户不太可能需要"蒙Baiti","微软维吾尔",甚至是"Webdings",当那些在名单这使得他们更难找到他们的字体不想要的.
SystemFontFamilies我可以用来将非符号罗马字母字体系列与其他字体系列分开,是否可以在对象上找到任何属性?
编辑:我想要使用的信息可以在Windows 7字体控制面板的"Designed for"字段中找到.此字段中的此字符串包含用于拉丁字母应用程序的字体的"拉丁语",用于"国际"字体的其他语言名称(例如,"Mongolian Baiti"是"蒙古语"),以及用于Wingdings等字体的"符号"."类别"字段对于将"显示"字体与"文本"字体分开也很有用.不幸的是,我无法弄清楚从代码中获取此信息的任何方法,我甚至无法弄清楚它在OpenType规范中的位置.我的猜测是涉及OpenType 脚本标签或语言标签.
Tim*_*oyd 12
字体中没有明确的信息明确定义它是否可读为"罗马".
您可以使用字形分析来查看所覆盖的字体的Unicode范围.这可以为您提供有关字体覆盖的语言的线索.但是,这也存在问题,例如:
雕文分析可能适用于缩小范围,但你可能会得到误报.
更新
我必须在我自己的应用程序中处理字体列表,所以不能单独留下这个!:)
实际上可以通过GlyphTypeface.Symbol属性(对我来说是新的)来推导字体是否是符号字体.因此,通过这个和一些字形分析,以下解决方案应该做到这一点.
然而,它仍然会找到"蒙古语Baiti"(并且它的"Baiti"不像咖喱风格的"Balti":))因为它有拉丁字符的字形所以它仍然是一个"罗马"字体,取决于你如何定义它.事实上,我系统上的所有非符号字体至少具有拉丁字符范围,因此拉丁字形测试实际上并不排除任何字体.
您对"Mongolian Baiti"的特别反对意见是什么?您希望如何自动排除它(例如,不使用手动维护的排除列表)?
[Test]
public void test()
{
var fonts = Fonts.SystemFontFamilies.OrderBy(x => x.ToString());
var latinFonts = fonts.Where(f =>
f.Source.StartsWith("Global") ||
(!IsSymbol(f) && HasLatinGlyphs(f)));
latinFonts.ToList().ForEach(Console.WriteLine);
}
private bool IsSymbol(FontFamily fontFamily)
{
GlyphTypeface glyph = GetFirstGlpyhTypeface(fontFamily);
return glyph.Symbol;
}
private bool HasLatinGlyphs(FontFamily fontFamily)
{
GlyphTypeface glyph = GetFirstGlpyhTypeface(fontFamily);
for (int i = 32; i < 127; i++)
{
if (!glyph.CharacterToGlyphMap.ContainsKey(i)) return false;
}
return true;
}
private GlyphTypeface GetFirstGlpyhTypeface(FontFamily fontFamily)
{
Typeface typeface = fontFamily.GetTypefaces().First();
GlyphTypeface glyph;
typeface.TryGetGlyphTypeface(out glyph);
return glyph;
}
Run Code Online (Sandbox Code Playgroud)
更新2
您可以尝试通过包含过滤器Latin Extended-A和Latin Extended-B范围,根据对扩展拉丁字符的支持来过滤掉字体.使用两者进行过滤Latin Extended-A并Latin Extended-B留下很少的字体,但只是过滤Latin Extended-A仍会留下相当多的字体.它也会自动删除,Mongolian Baiti因为它只支持Latin-1和Latin-1 Supplement.
这种分析是否给出了理想的结果是非常主观的.但要试验的东西:
private bool HasLatinGlyphs(FontFamily fontFamily)
{
GlyphTypeface glyph = GetFirstGlpyhTypeface(fontFamily);
List<Tuple<int, int>> ranges = new List<Tuple<int, int>>
{
new Tuple<int, int>(32, 126), //Latin-1
new Tuple<int, int>(160, 255), //Latin-1 Supplement
new Tuple<int, int>(256, 383), //Latin Extended-A
new Tuple<int, int>(384, 591), //Latin Extended-B
};
foreach (Tuple<int, int> range in ranges)
{
for (int i = range.Item1; i <= range.Item2; i++)
{
if (!glyph.CharacterToGlyphMap.ContainsKey(i)) return false;
}
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
同样,非常主观,但以下将提供支持拉丁字形的字体加上国际货币字符的子集:
List<Tuple<int, int>> ranges = new List<Tuple<int, int>>
{
new Tuple<int, int>(32, 126), //Latin-1
new Tuple<int, int>(0x20A0, 0x20B5), //Currency Symbols (Partial)
};
Run Code Online (Sandbox Code Playgroud)
更新3
继续你的问题编辑这里是一个适用于Windows 7的版本.它利用了Window 7的隐藏字体功能(如@Rick Sladkey所指出的),默认情况下隐藏了对当前用户的语言环境设置不被认为有用的字体.它还将排除符号字体:
[Test]
public void test()
{
var allFonts = Fonts.SystemFontFamilies.OrderBy(x => x.Source);
var filteredFonts = allFonts.Where(f =>
IsComposite(f) || (!IsSymbol(f) && !IsHidden(f)));
filteredFonts.ToList().ForEach(Console.WriteLine);
}
private static bool IsComposite(FontFamily fontFamily)
{
return fontFamily.Source.StartsWith("Global");
}
private static bool IsSymbol(FontFamily fontFamily)
{
Typeface typeface = fontFamily.GetTypefaces().First();
GlyphTypeface glyph;
typeface.TryGetGlyphTypeface(out glyph);
return glyph.Symbol;
}
private static bool IsHidden(FontFamily fontFamily)
{
const string Key = "Software\\Microsoft\\Windows NT\\CurrentVersion\\Font Management";
const string Value = "Inactive Fonts";
RegistryKey key = Registry.CurrentUser.OpenSubKey(Key);
IEnumerable<string> hiddenFonts = (string[])key.GetValue(Value);
return hiddenFonts.Contains(fontFamily.Source);
}
Run Code Online (Sandbox Code Playgroud)