如何确定字体是否为符号字体(例如Wingdings)

3

给定一个FontFamily,有没有办法确定这个字体是符号字体?

我在Windows Forms应用程序中尝试向用户显示字体列表,但我想删除仅为符号的字体,以便他们不能选择无法使用的字体。

4个回答

1

看到链接已经失效,我找出了当时编写此代码时所用的代码。

Namespace FontManagement

''' <summary>
''' Windows API Logical Font structure to represent information
''' about a font.
''' </summary>
<System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)> _
Public Structure LOGFONT
    ''' <summary>
    ''' Height of the font.
    ''' </summary>
    Public lfHeight As Integer
    Public lfWidth As Integer
    Public lfEscapement As Integer
    Public lfOrientation As Integer
    Public lfWeight As Integer
    Public lfItalic As Byte
    Public lfUnderline As Byte
    Public lfStrikeOut As Byte
    Public lfCharSet As Byte
    Public lfOutPrecision As Byte
    Public lfClipPrecision As Byte
    Public lfQuality As Byte
    Public lfPitchAndFamily As Byte
    <System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=32)> _
    Public lfFaceName As String
End Structure


''' <summary>
''' Enumeration of Panose Font Family Types.  These can be used for
''' determining the similarity of two fonts or for detecting non-character
''' fonts like WingDings.
''' </summary>
Public Enum PanoseFontFamilyTypes As Integer
    ''' <summary>
    '''  Any
    ''' </summary>
    PAN_ANY = 0
    ''' <summary>
    ''' No Fit
    ''' </summary>
    PAN_NO_FIT = 1
    ''' <summary>
    ''' Text and Display
    ''' </summary>
    PAN_FAMILY_TEXT_DISPLAY = 2
    ''' <summary>
    ''' Script
    ''' </summary>
    PAN_FAMILY_SCRIPT = 3
    ''' <summary>
    ''' Decorative
    ''' </summary>
    PAN_FAMILY_DECORATIVE = 4
    ''' <summary>
    ''' Pictorial                      
    ''' </summary>
    PAN_FAMILY_PICTORIAL = 5
End Enum


''' <summary>
''' Summary description for FontUtility.
''' </summary>
Public Class Utility

    <System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)> _
    Private Structure TEXTMETRIC
        Public tmHeight As Integer
        Public tmAscent As Integer
        Public tmDescent As Integer
        Public tmInternalLeading As Integer
        Public tmExternalLeading As Integer
        Public tmAveCharWidth As Integer
        Public tmMaxCharWidth As Integer
        Public tmWeight As Integer
        Public tmOverhang As Integer
        Public tmDigitizedAspectX As Integer
        Public tmDigitizedAspectY As Integer
        <System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=1)> _
        Public tmFirstChar As String
        <System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=1)> _
        Public tmLastChar As String
        <System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=1)> _
        Public tmDefaultChar As String
        <System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=1)> _
        Public tmBreakChar As String
        Public tmItalic As Byte
        Public tmUnderlined As Byte
        Public tmStruckOut As Byte
        Public tmPitchAndFamily As Byte
        Public tmCharSet As Byte
    End Structure


    Private Declare Function GetTextMetrics Lib "gdi32" ( _
     ByVal hdc As IntPtr, _
     ByRef lptm As TEXTMETRIC _
     ) As Integer

    Private Declare Function GetOutlineTextMetricsA Lib "gdi32" ( _
     ByVal hdc As IntPtr, _
     ByVal cbData As Integer, _
     ByVal lpOtm As IntPtr _
     ) As Integer

    Private Declare Function SelectObject Lib "gdi32" ( _
     ByVal hdc As IntPtr, _
     ByVal hObj As IntPtr _
     ) As IntPtr



    ''' <summary>
    ''' Gets the <see cref="PanoseFontFamilyTypes"/> for the specified font.
    ''' </summary>
    ''' <param name="graphics">A graphics object to use when detecting the Panose
    ''' family.</param>
    ''' <param name="font">The font to check.</param>
    ''' <returns>The Panose font family type.</returns>
    Public Shared Function PanoseFontFamilyType( _
     ByVal graphics As Graphics, _
      ByVal font As Font) As PanoseFontFamilyTypes
        Dim bFamilyType As Byte = 0

        Dim hdc As IntPtr = graphics.GetHdc()
        Dim hFontOld As IntPtr = SelectObject(hdc, font.ToHfont())

        Dim bufSize As Integer = GetOutlineTextMetricsA(hdc, 0, IntPtr.Zero)
        Dim lpOtm As IntPtr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(bufSize)
        System.Runtime.InteropServices.Marshal.WriteInt32(lpOtm, bufSize)
        Dim success As Integer = GetOutlineTextMetricsA(hdc, bufSize, lpOtm)
        If Not (success = 0) Then
            Dim offset As Integer = 61
            bFamilyType = System.Runtime.InteropServices.Marshal.ReadByte(lpOtm, offset)

            'byte bSerifStyle = Marshal.ReadByte(lpOtm, offset + 1); 
            'byte bWeight = Marshal.ReadByte(lpOtm, offset + 2); 
            'byte bProportion = Marshal.ReadByte(lpOtm, offset + 3); 
            'byte bContrast = Marshal.ReadByte(lpOtm, offset + 4); 
            'byte bStrokeVariation = Marshal.ReadByte(lpOtm, offset + 5); 
            'byte bArmStyle = Marshal.ReadByte(lpOtm, offset + 6); 
            'byte bLetterform = Marshal.ReadByte(lpOtm, offset + 7); 
            'byte bMidline = Marshal.ReadByte(lpOtm, offset + 8); 
            'byte bXHeight = Marshal.ReadByte(lpOtm, offset + 9); 
        End If

        System.Runtime.InteropServices.Marshal.FreeCoTaskMem(lpOtm)

        SelectObject(hdc, hFontOld)
        graphics.ReleaseHdc(hdc)

        Return CType(bFamilyType, PanoseFontFamilyTypes)

    End Function

    Private Sub New()

    End Sub

End Class

End Namespace

1

这是我做的。可能不是最好的解决方案,但效果很好:

private bool IsSymbol(FontFamily font) {
    Typeface typeface = font.GetTypefaces().First();
    typeface.TryGetGlyphTypeface(out GlyphTypeface glyph);
    return glyph == null || glyph.Symbol;
}

以下四种字体即使它们不是符号字体(Global momospace,Global Sans Serif,Global Serif和Global User Interface),也将返回true。因此,由于它们都包含单词“Global”,而方法捕获的符号字体中没有一个包含单词“Global”,所以我修改了该方法,以排除包含单词“Global”的字体,从而仅排除这4种字体。如下所示:
private bool IsSymbol(FontFamily font) {
    Typeface typeface = font.GetTypefaces().First();
    typeface.TryGetGlyphTypeface(out GlyphTypeface glyph);
    return (!font.Source.Contains("Global")) && (glyph == null || glyph.Symbol);
}

我知道这可能不是最好的解决方案,但对我来说完美地运作。所以你必须检查它是否与你的系统上存在的字体列表一起工作,或者修改它以使其正常工作。


0

谢谢,太棒了。我不知道为什么这个没有出现在我的搜索结果中。 - Paul Farry
1
这两个链接都已失效,所以此帖子现在没有用处了。 - Triynko
请仅发布解决方案,而不是链接。 - Mo'in Creemers

0

发布来自互联网档案馆的解决方案,来源于@user357254的回答。


检测字体是否为符号字体

虽然Font对象提供了许多关于字体的属性,但其中有一些并未包含。字体的Panose编号就是其中之一。这个属性是True Type字体定义的一部分,可用于字体匹配,并且对于确定特定字体类型的信息也非常有用(前提是字体的作者已经包含了该信息)。Panose编号的可能值如下:

  /// <summary>
  /// Enumeration of Panose Font Family Types.  These can be used for
  /// determining the similarity of two fonts or for detecting non-character
  /// fonts like WingDings.
  /// </summary>
  public enum PanoseFontFamilyTypes : int
  {
     /// <summary>
     ///  Any
     /// </summary>
     PAN_ANY = 0,
     /// <summary>
     /// No Fit
     /// </summary>
     PAN_NO_FIT = 1,
     /// <summary>
     /// Text and Display
     /// </summary>
     PAN_FAMILY_TEXT_DISPLAY = 2,
     /// <summary>
     /// Script
     /// </summary>
     PAN_FAMILY_SCRIPT = 3,
     /// <summary>
     /// Decorative
     /// </summary>
     PAN_FAMILY_DECORATIVE = 4,
     /// <summary>
     /// Pictorial                      
     /// </summary>
     PAN_FAMILY_PICTORIAL = 5
  }

唯一返回此信息的函数是GDI API调用GetOutlineTextMetrics,它返回关于字体的几乎所有您想知道的内容以及更多。该函数返回一个复杂的C结构,您可以使用InteropServices函数进行适应,但更容易阅读为一个内存块。这是我用来获取值的方法。第一次调用GetOutlineTextMetrics获取缓冲区所需的整个结构的大小;然后分配块并进行第二次调用以实际获取值。一旦块被填充,就是定位包含Panose成员的字节的问题,在ANSI调用的情况下,这在结构开始处的偏移量61处:
  [DllImport("gdi32", CharSet = CharSet.Ansi)]
  private static extern int GetOutlineTextMetrics(
     IntPtr hdc,            // handle to DC
     int cbData,            // size in bytes for text metrics
     IntPtr lpOtm         // pointer to buffer to receive outline text metrics structure
     );

  /// <summary>
  /// Gets the <see cref="PanoseFontFamilyTypes"/> for the specified font.
  /// </summary>
  /// <param name="graphics">A graphics object to use when detecting the Panose
  /// family.</param>
  /// <param name="font">The font to check.</param>
  /// <returns>The Panose font family type.</returns>
  public static PanoseFontFamilyTypes PanoseFontFamilyType(
      Graphics graphics, Font font)
  {
     byte bFamilyType = 0;

     IntPtr hdc = graphics.GetHdc();
     IntPtr hFontOld = SelectObject(hdc, font.ToHfont());

     int bufSize = GetOutlineTextMetrics(hdc, 0, IntPtr.Zero);
     IntPtr lpOtm = Marshal.AllocCoTaskMem(bufSize);
     Marshal.WriteInt32(lpOtm, bufSize);         
     int success = GetOutlineTextMetrics(hdc, bufSize, lpOtm);
     if (success != 0)
     {
        int offset = 61;
        bFamilyType = Marshal.ReadByte(lpOtm, offset); 
     }

     Marshal.FreeCoTaskMem(lpOtm);

     SelectObject(hdc, hFontOld);
     graphics.ReleaseHdc(hdc);
        
     return (PanoseFontFamilyTypes) bFamilyType;
     
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接