如何在 C# 中获取字体粗细?

How to get Font weight in C#?

我正在尝试获取字体的字体粗细,但这似乎需要 C# 中的某种巫毒魔法。

我找到并转换了这个枚举以帮助解决问题,我使用 FontDialog 选择字体。

    public enum FontWeight
    {
        Black = 900,
        UltraBold = 800,
        DemiBold = 600,
        Regular = 400,
        UltraLight = 200,
        Heavy = 900,
        ExtraBold = 800,
        Bold = 700,
        SemiBold = 600,
        Medium = 500,
        ExtraLight = 200,
        Thin = 100,
        DoNotCare = 0,
        Normal = 400,
        Light = 300
    }

然而,即使 FontDialog 允许我选择一些相应的字体样式,FontDialog 返回的字体仅包含 FontStyle(Bold, Italic, Regular, Strikeout, Underline) 的 C# 枚举中包含的样式。

例如,如果我选择一种具有 Light 样式的字体,则返回的字体将只有 Regular 样式。

有没有办法在 C# 中获取字体粗细?我不打算在程序本身中使用字体我只需要计算出另一个程序的重量。

这是我想出来的,不包括设计器代码。对不起,如果我用这个菜鸟代码冒犯了任何人。这使用 System.Windows.Media 中的 GlypTypeface class 获取大部分信息,并使用 LogFont 获取高度。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;


public partial class FontPicker : Form
{
    public Result ChoosenFont = new Result();

    private Dictionary<string, List<GlyphTypeface>> FontCollection = new Dictionary<string, List<GlyphTypeface>>();

    int[] sizes = new int[] { 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72 };

    public class Result
    {
        public string Name;
        public string Height;
        public string Weight;
    }


    public FontPicker(string currentFont)
    {
        InitializeComponent();

        foreach (int i in sizes)
        {
            listBoxSize.Items.Add(i);
        }

        int index = listBoxSize.FindStringExact("8");
        listBoxSize.SelectedIndex = index;

        var fontFilesPersonal = GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Microsoft\Windows\Fonts", new string[] { "*.ttf", "*.otf" }, SearchOption.TopDirectoryOnly);
        var fontFilesWindows = GetFiles(@"C:\Windows\Fonts", new string[] { "*.ttf", "*.otf" }, SearchOption.TopDirectoryOnly);

        List<string> fontFiles = new List<string>();

        fontFiles.AddRange(fontFilesWindows);
        fontFiles.AddRange(fontFilesPersonal);

        foreach (string fontFile in fontFiles)
        {
            GlyphTypeface ttf = new GlyphTypeface(new Uri(fontFile));

            string name = ttf.Win32FamilyNames.First().Value;

            if (!FontCollection.ContainsKey(name))
            {
                FontCollection.Add(name, new List<GlyphTypeface>());
            }

            FontCollection[name].Add(ttf);
        }

        var fonts = FontCollection.Keys.ToList();

        fonts.Sort();

        foreach (string name in fonts)
        {
            listBoxFonts.Items.Add(name);
        }

        index = listBoxFonts.FindStringExact(currentFont);
        if (index != -1) { listBoxFonts.SelectedIndex = index; }
        else
        {
            index = listBoxFonts.FindStringExact("Unispace");
            if (index != -1) { listBoxFonts.SelectedIndex = index; }
            else
            {
                index = listBoxFonts.FindStringExact("Arial");
                listBoxFonts.SelectedIndex = index;
            }

        }

    }

    public static IEnumerable<string> GetFiles(string path,
                   string[] searchPatterns,
                   SearchOption searchOption = SearchOption.TopDirectoryOnly)
    {
        return searchPatterns.AsParallel()
               .SelectMany(searchPattern =>
                      Directory.EnumerateFiles(path, searchPattern, searchOption));
    }

    private void buttonAccept_Click(object sender, EventArgs e)
    {
        FontWeight weight = (FontWeight)listBoxStyle.SelectedItem;
        string fontName = listBoxFonts.SelectedItem as string;
        int size = (int)listBoxSize.SelectedItem;

        LOGFONT logFont = new LOGFONT();

        Font lfont = (new Font(fontName, size, System.Drawing.FontStyle.Regular));
        lfont.ToLogFont(logFont);

        ChoosenFont.Weight = weight.ToOpenTypeWeight().ToString();
        ChoosenFont.Name = fontName;
        ChoosenFont.Height = logFont.lfHeight.ToString();

        DialogResult = DialogResult.OK;
        Close();
    }

    private void buttonCancel_Click(object sender, EventArgs e)
    {
        DialogResult = DialogResult.Cancel;
        Close();
    }

    private void listBoxFonts_SelectedIndexChanged(object sender, EventArgs e)
    {
        listBoxStyle.Items.Clear();
        string fontName = listBoxFonts.SelectedItem as string;

        if (FontCollection.ContainsKey(fontName))
        {
            foreach (var font in FontCollection[fontName])
            {
                if (!listBoxStyle.Items.Contains(font.Weight))
                    listBoxStyle.Items.Add(font.Weight);
            }
        }

        int index = listBoxStyle.FindStringExact("Normal");
        if (index == -1) { listBoxStyle.SelectedIndex = 0; }
        else { listBoxStyle.SelectedIndex = index; }

    }
}


public enum FontCharSet : byte
{
    ANSI_CHARSET = 0,
    DEFAULT_CHARSET = 1,
    SYMBOL_CHARSET = 2,
    SHIFTJIS_CHARSET = 128,
    HANGEUL_CHARSET = 129,
    HANGUL_CHARSET = 129,
    GB2312_CHARSET = 134,
    CHINESEBIG5_CHARSET = 136,
    OEM_CHARSET = 255,
    JOHAB_CHARSET = 130,
    HEBREW_CHARSET = 177,
    ARABIC_CHARSET = 178,
    GREEK_CHARSET = 161,
    TURKISH_CHARSET = 162,
    VIETNAMESE_CHARSET = 163,
    THAI_CHARSET = 222,
    EASTEUROPE_CHARSET = 238,
    RUSSIAN_CHARSET = 204,
    MAC_CHARSET = 77,
    BALTIC_CHARSET = 186,
}
public enum FontPrecision : byte
{
    OUT_DEFAULT_PRECIS = 0,
    OUT_STRING_PRECIS = 1,
    OUT_CHARACTER_PRECIS = 2,
    OUT_STROKE_PRECIS = 3,
    OUT_TT_PRECIS = 4,
    OUT_DEVICE_PRECIS = 5,
    OUT_RASTER_PRECIS = 6,
    OUT_TT_ONLY_PRECIS = 7,
    OUT_OUTLINE_PRECIS = 8,
    OUT_SCREEN_OUTLINE_PRECIS = 9,
    OUT_PS_ONLY_PRECIS = 10,
}
public enum FontClipPrecision : byte
{
    CLIP_DEFAULT_PRECIS = 0,
    CLIP_CHARACTER_PRECIS = 1,
    CLIP_STROKE_PRECIS = 2,
    CLIP_MASK = 0xf,
    CLIP_LH_ANGLES = (1 << 4),
    CLIP_TT_ALWAYS = (2 << 4),
    CLIP_DFA_DISABLE = (4 << 4),
    CLIP_EMBEDDED = (8 << 4),
}
public enum FontQuality : byte
{
    DEFAULT_QUALITY = 0,
    DRAFT_QUALITY = 1,
    PROOF_QUALITY = 2,
    NONANTIALIASED_QUALITY = 3,
    ANTIALIASED_QUALITY = 4,
    CLEARTYPE_QUALITY = 5,
    CLEARTYPE_NATURAL_QUALITY = 6,
}
[Flags]
public enum FontPitchAndFamily : byte
{
    DEFAULT_PITCH = 0,
    FIXED_PITCH = 1,
    VARIABLE_PITCH = 2,
    FF_DONTCARE = (0 << 4),
    FF_ROMAN = (1 << 4),
    FF_SWISS = (2 << 4),
    FF_MODERN = (3 << 4),
    FF_SCRIPT = (4 << 4),
    FF_DECORATIVE = (5 << 4),
}

// if we specify CharSet.Auto instead of CharSet.Ansi, then the string will be unreadable
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class LOGFONT
{
    public int lfHeight;
    public int lfWidth;
    public int lfEscapement;
    public int lfOrientation;
    public FontWeight lfWeight;
    [MarshalAs(UnmanagedType.U1)]
    public bool lfItalic;
    [MarshalAs(UnmanagedType.U1)]
    public bool lfUnderline;
    [MarshalAs(UnmanagedType.U1)]
    public bool lfStrikeOut;
    public FontCharSet lfCharSet;
    public FontPrecision lfOutPrecision;
    public FontClipPrecision lfClipPrecision;
    public FontQuality lfQuality;
    public FontPitchAndFamily lfPitchAndFamily;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string lfFaceName;

    public override string ToString()
    {
        StringBuilder sb = new StringBuilder();
        sb.Append("LOGFONT\n");
        sb.AppendFormat("   lfHeight: {0}\n", lfHeight);
        sb.AppendFormat("   lfWidth: {0}\n", lfWidth);
        sb.AppendFormat("   lfEscapement: {0}\n", lfEscapement);
        sb.AppendFormat("   lfOrientation: {0}\n", lfOrientation);
        sb.AppendFormat("   lfWeight: {0}\n", lfWeight);
        sb.AppendFormat("   lfItalic: {0}\n", lfItalic);
        sb.AppendFormat("   lfUnderline: {0}\n", lfUnderline);
        sb.AppendFormat("   lfStrikeOut: {0}\n", lfStrikeOut);
        sb.AppendFormat("   lfCharSet: {0}\n", lfCharSet);
        sb.AppendFormat("   lfOutPrecision: {0}\n", lfOutPrecision);
        sb.AppendFormat("   lfClipPrecision: {0}\n", lfClipPrecision);
        sb.AppendFormat("   lfQuality: {0}\n", lfQuality);
        sb.AppendFormat("   lfPitchAndFamily: {0}\n", lfPitchAndFamily);
        sb.AppendFormat("   lfFaceName: {0}\n", lfFaceName);

        return sb.ToString();
    }
}

编辑:修复了代码中的一些错误。