【问题标题】:Enumerate supported characters/glyphs in a specific font with UWP/C#使用 UWP/C# 枚举特定字体中支持的字符/字形
【发布时间】:2023-03-22 14:20:02
【问题描述】:

试图弄清楚 Windows 10 (UWP) 商店应用程序中是否有一种方法可以枚举或列出特定字体中支持的字符(旁注:我需要“检查”的字体本地存储在应用程序中包裹)。

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

感谢任何帮助!

【问题讨论】:

    标签: c# uwp windows-10-universal


    【解决方案1】:

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

    您可以使用 IDWriteFontFace::GetGlyphIndices method 通过 DirectWrite 检查字体是否将字形映射到特定的 Unicode 字符/代码。作为 SharpDx 库的一部分,DirectWrite 有一个 C# 包装器,特别是 SharpDX.Direct2D1 package on nuget

    我从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]);
                        }
                    }
                }
            }
    
        }
    }
    

    【讨论】:

    • 这看起来很有希望 - 我唯一的问题是我正在使用的字体文件不是系统字体,而是存储在本地。知道这是否适用于字体文件,例如: /Fonts/AnonymousPro-regular.ttf#Anonymous Pro ?
    • SharpDx github 有一个使用自定义字体的示例,在这里复制有点长。 Take a look
    • 在搜索了代码之后,我仍然没有获得与 SharpDx 一起使用的自定义字体的运气。我知道乞丐不能选择,但希望有一个更直接的解决方案......
    • 您遇到了什么问题?也许它与字体本身有关,你能上传一些吗?
    • 谢谢埃文 - 我搞定了!性能是一个小问题,但在扫描 10,000 个字形中的每一个字形时都可以预期。对于只需要字形数量的任何人,可以使用具有更快性能的 fontface.GlyphCount。
    猜你喜欢
    • 2012-05-11
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-18
    • 2011-05-26
    • 2011-01-04
    • 2017-07-14
    相关资源
    最近更新 更多