gpt4 book ai didi

WPF:如何从 Fonts.SystemFontFamilies 中过滤掉非罗马字体?

转载 作者:行者123 更新时间:2023-12-04 10:21:35 25 4
gpt4 key购买 nike

我知道如何使用几行 XAML 创建 WPF 字体选择器,绑定(bind)到 Fonts.SystemFontFamilies ( thanks to Norris Cheng's excellent blog post ),但我不知道如何过滤掉所有国际和其他非罗马字母字体系列。我的用户不太可能需要“Mongolian Baiti”、“Microsoft Uighur”甚至“Webdings”,当它们在列表中时,他们就更难找到他们想要的字体 想。

SystemFontFamilies 访问的对象是否有任何属性?我可以用它来将非符号罗马字母字体系列与其他字体系列分开吗?

编辑:我想使用的信息可在 Windows 7 字体控制面板的“专为”字段中找到。此字段中的此字符串包含“Latin”(用于拉丁字母应用程序的字体)、“international”字体的其他语言名称(例如,“Mongolian Baiti”是“Mongolian”),以及用于 Wingdings 等字体的“Symbol”。 “类别”字段对于将“显示”字体与“文本”字体分开看起来也很有用。不幸的是,我想不出任何办法从代码中获取这些信息,我什至想不出它在 OpenType spec 中的位置。 .我的猜测是 OpenType script tagslanguage tags参与其中。

最佳答案

字体中没有明确定义它是否可读为“罗马”的明确信息。

您可以借助字形分析来查看字体涵盖的 Unicode 范围。这可以为您提供有关字体涵盖哪些语言的线索。但是,这也有问题,例如:

  • 默认的 Windows 7 字体是“Segoe UI”。在您的方案中,您会将其视为“罗马”字体吗?这里的问题是,即使您进行字形分析,它也涵盖了拉丁语以及其他 Unicode 范围,例如阿拉伯语和泰语。好的,我们可以包含至少涵盖拉丁语的字体,但是,如果拉丁语范围实际上不像第 3 点中的拉丁语那样可读怎么办?
  • “Mongolian Baiti”的示例包括涵盖基本拉丁语范围的字形,因此可用于渲染“Roman”文本。
  • Webdings 涵盖了拉丁语范围,因此通过分析它可以通过,但它实际上并不包含可读的拉丁字符。

  • 也许可以应用字形分析来缩小范围,但您可能会得到误报。

    更新

    我必须在我自己的应用程序中处理字体列表,所以不能单独留下这个! :)

    实际上可以通过 GlyphTypeface.Symbol 推导出一个字体是否是符号字体。属性(property)(这对我来说是新的)。因此,通过这个和一些字形分析,以下解决方案应该可以解决问题。

    然而,它仍然会找到“Mongolian Baiti”(它是“Baiti”而不是 curry 风格的“Balti”:)),因为它有拉丁字符的字形,所以它仍然是“罗马”字体,具体取决于你如何定义它。事实上,我系统上的所有非符号字体都至少有拉丁字符范围,所以拉丁字形测试实际上并没有排除任何字体。

    您对“蒙古白提”有什么特别的反对意见,您希望如何自动排除它(例如,不使用手动维护的排除列表)?
    [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;
    }

    更新 2

    您可以通过包含 Latin Extended-A 的过滤器来尝试根据它们对扩展拉丁字符的支持来过滤掉字体。和 Latin Extended-B范围。过滤 Latin Extended-ALatin Extended-B留下很少的字体,但只是过滤 Latin Extended-A仍然留下了相当多的字体。它还会自动删除 Mongolian Baiti因为这只支持 Latin-1Latin-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;
    }

    同样,非常主观,但以下将提供支持拉丁字形和国际货币字符子集的字体:
    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)
    };

    更新 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);
    }

    关于WPF:如何从 Fonts.SystemFontFamilies 中过滤掉非罗马字体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4798370/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com