使用 UWP/C# 枚举特定字体支持的 characters/glyphs

Enumerate supported characters/glyphs in a specific font with UWP/C#

试图找出 Windows10 (UWP) 商店应用程序中是否有一种方法可以枚举或列出特定字体中支持的字符(旁注:我需要的字体 'inspect' 本地存储在应用程序包中)。

similar answers 适用于 Win32 应用程序,但我没有看到任何适用于 UWP 应用程序的应用程序。

感谢任何帮助!

新答案 - 检查自定义字体文件

您可以使用 IDWriteFontFace::GetGlyphIndices method. There is a C# wrapper for DirectWrite as part of the SharpDx library, specifically the SharpDX.Direct2D1 package on nuget.

通过 DirectWrite 检查字体是否将字形映射到特定的 Unicode character/code

我从SharpDx Directwrite example on github做了一个例子。我使用文件选择器对话框打开文件,因为 UWP 应用程序不允许访问大部分文件系统,除非用户自己选择文件。您还可以将字体与您的应用程序一起使用。我下载了两种免费字体来测试,“Aileron”和“Grundschrift”。我只是非常快速地把它搞定,向您展示它并不难,但我确信代码没有遵循最佳实践。首先,从 SharpDx Directwrite 自定义字体示例中添加以下三个 类:ResourceFontFileStream.csResourceFontLoader.csResourceFontFileEnumerator.cs。将命名空间更改为您的项目命名空间。在 ResourceFontLoader.cs 中将构造函数更改为:

public ResourceFontLoader(Factory factory, List<Stream> fontfiles)
{
    _factory = factory;
    var AnyFontsLoaded = false;
    foreach (var filename in fontfiles)
    {
        try
        {
            using (filename)
            {
                var fontBytes = Utilities.ReadStream(filename);
                var stream = new DataStream(fontBytes.Length, true, true);
                stream.Write(fontBytes, 0, fontBytes.Length);
                stream.Position = 0;
                _fontStreams.Add(new ResourceFontFileStream(stream));
                AnyFontsLoaded = true;
            }
        }
        catch (System.Exception)
        {
            // Handle all file exceptions how you see fit
            throw;
        }
    }
    if (AnyFontsLoaded)
    {
        // Build a Key storage that stores the index of the font
        _keyStream = new DataStream(sizeof(int) * _fontStreams.Count, true, true);
        for (int i = 0; i < _fontStreams.Count; i++)
            _keyStream.Write((int)i);
        _keyStream.Position = 0;

        // Register the 
        _factory.RegisterFontFileLoader(this);
        _factory.RegisterFontCollectionLoader(this);
    }
}

在您的测试主页中:

public sealed partial class MainPage : Page
{
    public ResourceFontLoader CurrentResourceFontLoader { get; set; }
    public FontCollection CurrentFontCollection { get; set; }
    public SharpDX.DirectWrite.Factory FactoryDWrite { get; private set; }
    public List<Stream> customFontStreams { get; set; }
    public List<string> FontFamilyNames { get; set; }
    public MainPage()
    {
        customFontStreams = new List<Stream>();
        this.InitializeComponent();
    }

    async Task LoadCustomFonts()
    {
        await Task.Run(() =>
        {
            // Font Families
            FontFamilyNames = new List<string> { "Aileron", "Grundschrift" };
            // Character codes to check for:
            int[] codes = { 0x41, 0x6f, 0x7c, 0xc2aa, 0xD7A3 };
            FactoryDWrite = new SharpDX.DirectWrite.Factory();
            CurrentResourceFontLoader = new ResourceFontLoader(FactoryDWrite, customFontStreams);
            CurrentFontCollection = new FontCollection(FactoryDWrite, CurrentResourceFontLoader, CurrentResourceFontLoader.Key);

            foreach (var fontfamilyname in FontFamilyNames)
            {
                int familyIndex;
                CurrentFontCollection.FindFamilyName(fontfamilyname, out familyIndex);

                using (var fontFamily = CurrentFontCollection.GetFontFamily(familyIndex))
                {
                    var font = fontFamily.GetFont(0);

                    using (var fontface = new FontFace(font))
                    {
                        var results = fontface.GetGlyphIndices(codes);
                        for (int i = 0; i < codes.Length - 1; i++)
                        {
                            if (results[i] > 0)
                            {
                                Debug.WriteLine("Contains the unicode character " + codes[i]);

                            }
                            else
                            {
                                Debug.WriteLine("Does not contain the unicode character " + codes[i]);
                            }
                        }
                    }
                }

            }
        });

    }
    private async void button_Click(object sender, RoutedEventArgs e)
    {
        FileOpenPicker openPicker = new FileOpenPicker();
        openPicker.ViewMode = PickerViewMode.List;
        openPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
        openPicker.FileTypeFilter.Add(".otf");
        openPicker.FileTypeFilter.Add(".ttf");
        IReadOnlyList<StorageFile> files = await openPicker.PickMultipleFilesAsync();
        if (files.Count > 0)
        {


            // Application now has read/write access to the picked file(s) 
            foreach (StorageFile file in files)
            {
                customFontStreams.Add(await file.OpenStreamForReadAsync());
            }
            await LoadCustomFonts();
        }
    }
}

原答案-检查系统字体:

使用 SharpDX.Direct2D1 包检查字体是否具有特定字符的示例:

var fontName = "Segoe UI";

using (var factory = new Factory(FactoryType.Shared))
{
    using (var fontCollection = factory.GetSystemFontCollection(true))
    {
        int familyIndex;
        fontCollection.FindFamilyName(fontName, out familyIndex);

        using (var fontFamily = fontCollection.GetFontFamily(familyIndex))
        {
            var font = fontFamily.GetFont(0);

            using (var fontface = new FontFace(font))
            {
                int[] codes = { 0x41, 0x6f, 0x7c, 0xc2aa, 0xD7A3 };

                var results = fontface.GetGlyphIndices(codes);
                for (int i = 0; i < codes.Length - 1; i++)
                {
                    if (results[i] > 0)
                    {
                        Debug.WriteLine("Contains the unicode character " + codes[i]);
                    }
                    else
                    {
                        Debug.WriteLine("Does not contain the unicode character " + codes[i]);
                    }
                }
            }
        }

    }
}