Retrieve Filename of a font

ぐ巨炮叔叔 提交于 2020-06-15 23:42:53

问题


I would like to get the filename of a font. This can't be that hard... I am aware, there is a very similar question already, but the answer to that question just can't be it.

What I want to do is to send a Font file over TCP/IP to an other client, if he requests it. I select the desired font over a FontDialog, I can get the FontName from the framework. I can't find the font file in a way that I can say will work most of the time.

Where does .NET know which fonts are installed on the system? It can't be that the framework relies on a solution which does not work all the time, like the solution on CodeProject and suggested in Stackoverflow. There must be a secure way to retrieve the font file. The FontDialog can list them all in a box and the fonts installed must have a path to their file.

Anyone interested in helping me?

enter image description here


回答1:


using System;
using System.Drawing;
using System.Text.RegularExpressions;
using Microsoft.Win32

 

public static string GetSystemFontFileName(Font font)
{
    RegistryKey fonts = null;
    try{
        fonts = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Windows NT\CurrentVersion\Fonts", false);
        if(fonts == null)
        {
            fonts = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Fonts", false);
            if(fonts == null)
            {
                throw new Exception("Can't find font registry database.");
            }
        }

        string suffix = "";
        if(font.Bold)
            suffix += "(?: Bold)?";
        if(font.Italic)
            suffix += "(?: Italic)?";

        var regex = new Regex(@"^(?:.+ & )?"+Regex.Escape(font.Name)+@"(?: & .+)?(?<suffix>"+suffix+@") \(TrueType\)$", RegexOptions.Compiled);

        string[] names = fonts.GetValueNames();

        string name = names.Select(n => regex.Match(n)).Where(m => m.Success).OrderByDescending(m => m.Groups["suffix"].Length).Select(m => m.Value).FirstOrDefault();

        if(name != null)
        {
            return fonts.GetValue(name).ToString();
        }else{
            return null;
        }
    }finally{
        if(fonts != null)
        {
            fonts.Dispose();
        }
    }
}



回答2:


For one, your problem describes issues with Windows OS. Hence your solution needs to be a Windows specific solution. In your comment you mentioned that the solution may not work on other OS.

It surely WILL NOT work.

Each OS will needs to be handled separately. Also, you can't assume that installation of fonts will happen in the same way on client's OS.

As for the problem with getting font file names. There is nothing wrong with the solutions provided on CP. In many instances the only way to get something in windows is to make API calls. .Net simply has no support for a number of things we may need to do. So relying on API is doesn't make it automatically wrong or undesirable.

EDIT:

In .NET 4.0 Fonts is a special folder that can be accessed like so

var fontsFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.Fonts);



回答3:


    Dictionary<string, List<string>> _fontNameToFiles; 
    /// <summary>
    /// This is a brute force way of finding the files that represent a particular
    /// font family.
    /// The first call may be quite slow.
    /// Only finds font files that are installed in the standard directory.
    /// Will not discover font files installed after the first call.
    /// </summary>
    /// <returns>enumeration of file paths (possibly none) that contain data
    /// for the specified font name</returns>
    private IEnumerable<string> GetFilesForFont(string fontName)
    {
        if (_fontNameToFiles == null)
        {
            _fontNameToFiles = new Dictionary<string, List<string>>();
            foreach (var fontFile in Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.Fonts)))
            {
                var fc = new PrivateFontCollection();
                try
                {
                    fc.AddFontFile(fontFile);
                }
                catch (FileNotFoundException)
                {
                    continue; // not sure how this can happen but I've seen it.
                }
                var name = fc.Families[0].Name;
                // If you care about bold, italic, etc, you can filter here.
                List<string> files;
                if (!_fontNameToFiles.TryGetValue(name, out files))
                {
                    files = new List<string>();
                    _fontNameToFiles[name] = files;
                }
                files.Add(fontFile);
            }
        }
        List<string> result;
        if (!_fontNameToFiles.TryGetValue(fontName,  out result))
            return new string[0];
        return result;
    }


来源:https://stackoverflow.com/questions/21525377/retrieve-filename-of-a-font

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!