净列举的WinForms字体样式? [英] .Net enumerate winforms font styles?

查看:163
本文介绍了净列举的WinForms字体样式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在摸索一种方式来列出有效的字体样式使用.NET Framework(即使我要的PInvoke GDI32或其他一些API),因为不是所有的字体落入System.Drawing中给定的字体。 fontstyle的枚举值(粗体,斜体,普通,删除线,下划线)。不符合该法案的字体的一个很好的例子是的Segoe UI,这是TrueType字体微软与字体样式:普通,Semibold,轻,粗体,斜体,和BOLDITALIC。另一个例子是宋体有:普通,精细,斜体,粗体,粗斜体,大胆窄,窄粗斜体,窄斜体

在Windows 7中(可能是Vista的为好,但我没有一台机器检查),当您打​​开资源管理器,浏览到%SYSTEMROOT%\字体,你会看到一个名为字体风格一栏,列出所有的可用样式的每个字体,告诉我说,肯定是有办法做到这一点,最起码通过API调用。

最后,我期待枚举的FontFamily列表,然后列出每个家庭每个字体样式。下面是示例code上市了所有的字体系列,如果任何人都可以用于列出可用于每个家庭的字体样式提供帮助,我愿意AP preciate它。如果我要对这个错误的方式,我绝对愿意听取建议。

  Drawing.Text.InstalledFontCollection国际金融公司(IFC)=新Drawing.Text.InstalledFontCollection();
的foreach(FF的FontFamily在ifc.Families)
{
    Console.WriteLine(ff.ToString());
    //这样的事情将是很好的,但AFAIK没有类似的存在
    / *
    的foreach(在ff.Styles fontstyle的风格)
        Console.WriteLine(style.ToString());
    * /
}
 

解决方案

好吧,这将是一个很大的低于code。首先,这是因为TTF文件的TTF结构和字节序的。在code不是原来我的,它来自我已经移植到VB.NET和周围进行了一些修改几个来源。请参见此页一个C ++版本,获取的字体名称。

这code通过在注册表中安装的字体读取(无论是在%WINDIR%\字体或其他地方),过滤器,只得到那些与扩展名为.ttf(如.FON和.ttc被忽略),然后将其通过这些字体文件路径常规, GetFontDetails ,读通过,并得到字体名称(uNameID#1)和字体的一个子系列(又名风格,uNameID#2)。如果您有兴趣获得更多的性能比,去名字 - 命名表微软的版式网站和搜索您的浏览器的名称标识的。然后,它踢出来的字体名称,字体亚科和字体路径控制台窗口。

创建一个新的VB.NET控制台应用程序,并粘贴到下面了模块1 code和preSS <大骨节病> F5

事不宜迟:

 进口System.Linq的
进口System.IO
进口System.Text

模块模块1
    副主()
        昏暗allInstalledFonts =从e在My.Computer.Registry.LocalMachine.OpenSubKey(SOFTWARE \\ \\微软的Windows NT \\ \\ CURRENTVERSION字体)。GetValueNames
                                 选择My.Computer.Registry.LocalMachine.OpenSubKey(SOFTWARE \\ \\微软的Windows NT \\ \\ CURRENTVERSION字体)。的GetValue(五)
        昏暗的ttfFonts =从e在allInstalledFonts.Where(功能(E)e.ToString.EndsWith(TTF)或e.ToString.EndsWith(OTF))
        昏暗的ttfFontsPaths =从e在ttfFonts.Select(功能(e)如(Path.GetPathRoot(e.ToString)=,Environment.GetFolderPath(Environment.SpecialFolder.Fonts)及\&放大器; e.ToString,E的ToString))
        昏暗的字体=从电子作为字符串在ttfFontsPaths选择GetFontDetails(e.ToString)

        对于每个F作为InstalledFont的字体
            Console.WriteLine(姓名:&放大器; f.FontName&安培;,亚科:&放大器; f.FontSubFamily&安培;路径:&放大器; f.FontPath)
        下一个
        到Console.ReadLine()
    结束小组
    公共类InstalledFont
        物业字体名作为字符串
        物业FontSubFamily作为字符串
        物业字体路径作为字符串
        亚新(BYVAL名作为字符串,BYVAL亚科作为字符串,BYVAL路径作为字符串)
            字体名=名称
            FontSubFamily =亚科
            字体路径=路径
        结束小组
    末级
    公共职能GetFontDetails(BYVAL fontFilePath作为字符串)作为InstalledFont
        FONTNAME暗淡作为字符串=的String.Empty
        昏暗FontSubFamily作为字符串=的String.Empty
        昏暗encStr =UTF-8
        昏暗strRet作为字符串=的String.Empty

        使用FS作为新的FileStream(fontFilePath,FileMode.Open,FileAccess.Read)
            昏暗ttOffsetTable作为新TT_OFFSET_TABLE
            随着ttOffsetTable
                .uMajorVersion = ReadUShort(FS)
                .uMinorVersion = ReadUShort(FS)
                .uNumOfTables = ReadUShort(FS)
                .uSearchRange = ReadUShort(FS)
                .uEntrySelector = ReadUShort(FS)
                .uRangeShift = ReadUShort(FS)
            结束与

            如果ttOffsetTable.uMajorVersion&LT;&GT; 1或ttOffsetTable.uMinorVersion&LT;&GT; 0然后
                返回任何结果
            结束如果

            昏暗tblDir作为新TT_TABLE_DIRECTORY
            昏暗发现由于布尔= FALSE

            对于我作为整数= 0〜ttOffsetTable.uNumOfTables
                随着tblDir
                    。初始化()
                    fs.Read(.szTag,0,.szTag.Length)
                    .uCheckSum = ReadULong(FS)
                    .uOffset = ReadULong(FS)
                    .uLength = ReadULong(FS)
                结束与

                昏暗ENC作为编码= Encoding.GetEncoding(encStr)

                昏暗的参考译文字符串= enc.GetString(tblDir.szTag)
                如果STRCOMP(S,名)= 0然后
                    发现= TRUE
                    退出对于
                结束如果
            下一个

            如果找不到,则返回任何结果

            fs.Seek(tblDir.uOffset,SeekOrigin.Begin)
            昏暗ttNTHeader作为新TT_NAME_TABLE_HEADER
            随着ttNTHeader
                .uFSelector = ReadUShort(FS)
                .uNRCount = ReadUShort(FS)
                .uStorageOffset = ReadUShort(FS)
            结束与

            昏暗ttRecord作为新TT_NAME_RECORD

            对于j为整数= 0要ttNTHeader.uNRCount
                随着ttRecord
                    .uPlatformID = ReadUShort(FS)
                    .uEncodingID = ReadUShort(FS)
                    .uLanguageID = ReadUShort(FS)
                    .uNameID = ReadUShort(FS)
                    .uStringLength = ReadUShort(FS)
                    .uStringOffset = ReadUShort(FS)
                结束与

                如果ttRecord.uNameID&GT; 2然后退出对于

                昏暗的非营利组织作为整数= fs.Position
                fs.Seek(tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset,SeekOrigin.Begin)

                昏暗的BUF(ttRecord.uStringLength  -  1)为字节
                fs.Read(BUF,0,ttRecord.uStringLength)

                昏暗的ENC作为编码
                如果ttRecord.uEncodingID = 3或ttRecord.uEncodingID = 1,则
                    ENC = Encoding.BigEndianUni code
                其他
                    ENC = Encoding.UTF8
                结束如果

                strRet = enc.GetString(BUF)
                如果ttRecord.uNameID = 1,则字体名= strRet
                如果ttRecord.uNameID = 2那么FontSubFamily = strRet
                fs.Seek(非营利组织,SeekOrigin.Begin)
            下一个
            返回新InstalledFont(字体名称,FontSubFamily,fontFilePath)
        结束使用
    端功能
    公共结构TT_OFFSET_TABLE
        公共uMajorVersion与ushort
        公共uMinorVersion与ushort
        公共uNumOfTables与ushort
        公共uSearchRange与ushort
        公共uEntrySelector与ushort
        公共uRangeShift与ushort
    末端结构
    公共结构TT_TABLE_DIRECTORY
        公共szTag()作为字节
        公共uCheckSum由于UInt32的
        公共uOffset由于UInt32的
        公共uLength由于UInt32的
        公用Sub初始化()
            REDIM szTag(3)
        结束小组
    末端结构
    公共结构TT_NAME_TABLE_HEADER
        公共uFSelector与ushort
        公共uNRCount与ushort
        公共uStorageOffset与ushort
    末端结构
    公共结构TT_NAME_RECORD
        公共uPlatformID与ushort
        公共uEncodingID与ushort
        公共uLanguageID与ushort
        公共uNameID与ushort
        公共uStringLength与ushort
        公共uStringOffset与ushort
    末端结构
    专用功能ReadChar(为ByRef FS作为的FileStream,BYVAL字符作为整数)作为UINT16
        昏暗的S(字符)作为字符串
        昏暗的BUF(CByte(s.Length))为字节
        BUF = ReadAndSwap(FS,buf.Length)
        返回BitConverter.ToUInt16(BUF,0)
    端功能
    专用功能ReadByte(为ByRef FS作为的FileStream)作为UINT16
        昏暗的BUF(10)为字节
        BUF = ReadAndSwap(FS,buf.Length)
        返回BitConverter.ToUInt16(BUF,0)
    端功能
    专用功能ReadUShort(为ByRef FS作为的FileStream)作为UINT16
        昏暗的BUF(1)字节
        BUF = ReadAndSwap(FS,buf.Length)
        返回BitConverter.ToUInt16(BUF,0)
    端功能
    专用功能ReadULong(为ByRef FS作为的FileStream)作为UInt32的
        昏暗的BUF(3)为字节
        BUF = ReadAndSwap(FS,buf.Length)
        返回BitConverter.ToUInt32(BUF,0)
    端功能
    专用功能ReadAndSwap(为ByRef FS作为的FileStream,BYVAL大小为整数)为字节()
        昏暗的buf(大小 -  1)为字节
        fs.Read(BUF,0,buf.Length)
        Array.Reverse(BUF)
        返回BUF
    端功能
前端模块
 

I have been searching around for a way to list the valid font styles for a given font using the .Net framework (even if I have to pinvoke gdi32 or some other API) since not all fonts fall into the System.Drawing.FontStyle enum values (Bold, Italic, Regular, Strikeout, Underline). A perfect example of a font that does not fit the bill is Segoe UI, which is a TrueType Microsoft font, with font styles of: Regular, Semibold, Light, Bold, Italic, and BoldItalic. Another example is Arial which has: Regular, Narrow, Italic, Bold, Bold Italic, Narrow Bold, Narrow Bold Italic, and Narrow Italic.

In Windows 7 (probably vista as well, but I don't have a machine to check) when you open explorer and browse to %SystemRoot%\Fonts you will see a column called "Font style" which lists out all of the available styles for each font, which tells me that there is definitely a way to do this, at the very least through API calls.

Ultimately, I am looking to enumerate the FontFamily list, and then list out every font style for each family. Below is sample code for listing out all of the font families, if anyone could provide assistance for listing the font styles available for each family, I would appreciate it. If I am going about this the wrong way, I am definitely open to suggestions.

Drawing.Text.InstalledFontCollection ifc = new Drawing.Text.InstalledFontCollection();
foreach ( FontFamily ff in ifc.Families )
{
    Console.WriteLine(ff.ToString());
    // Something like this would be nice, but AFAIK nothing similar exists
    /*
    foreach ( FontStyle style in ff.Styles )
        Console.WriteLine(style.ToString());
    */
}

解决方案

Okay, this is going to be a lot of code below. Primarily, it is because of the TTF structures and Endianess of TTF files. The code is not originally mine, it's come from a few sources that I've ported to VB.NET and changed a few things around. See this page for a C++ version that gets the font name.

This code reads through the registry for installed fonts (whether in %windir%\fonts or elsewhere), filters to only get ones with the .ttf extension (e.g. .fon and .ttc are ignored) and then it passes these font file paths to a routine, GetFontDetails, that reads through and gets the Font Name (uNameID #1) and Font Sub Family (aka Style, uNameID #2). If you are interested in getting more properties than those, go to name - Naming Table on Microsoft's Typography website and search in your browser for Name IDs. It then kicks out the Font Name, Font SubFamily and Font Path to the Console window.

Create a new VB.NET Console app and paste the below in over Module1 code and press F5.

Without further ado:

Imports System.Linq
Imports System.IO
Imports System.Text

Module Module1
    Sub Main()
        Dim allInstalledFonts = From e In My.Computer.Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts").GetValueNames
                                 Select My.Computer.Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts").GetValue(e)
        Dim ttfFonts = From e In allInstalledFonts.Where(Function(e) e.ToString.EndsWith(".ttf") Or e.ToString.EndsWith(".otf"))
        Dim ttfFontsPaths = From e In ttfFonts.Select(Function(e) If(Path.GetPathRoot(e.ToString) = "", Environment.GetFolderPath(Environment.SpecialFolder.Fonts) & "\" & e.ToString, e.ToString))
        Dim fonts = From e As String In ttfFontsPaths Select GetFontDetails(e.ToString)

        For Each f As InstalledFont In fonts
            Console.WriteLine("Name: " & f.FontName & ", SubFamily: " & f.FontSubFamily & ", Path: " & f.FontPath)
        Next
        Console.ReadLine()
    End Sub
    Public Class InstalledFont
        Property FontName As String
        Property FontSubFamily As String
        Property FontPath As String
        Sub New(ByVal name As String, ByVal subfamily As String, ByVal path As String)
            FontName = name
            FontSubFamily = subfamily
            FontPath = path
        End Sub
    End Class
    Public Function GetFontDetails(ByVal fontFilePath As String) As InstalledFont
        Dim FontName As String = String.Empty
        Dim FontSubFamily As String = String.Empty
        Dim encStr = "UTF-8"
        Dim strRet As String = String.Empty

        Using fs As New FileStream(fontFilePath, FileMode.Open, FileAccess.Read)
            Dim ttOffsetTable As New TT_OFFSET_TABLE
            With ttOffsetTable
                .uMajorVersion = ReadUShort(fs)
                .uMinorVersion = ReadUShort(fs)
                .uNumOfTables = ReadUShort(fs)
                .uSearchRange = ReadUShort(fs)
                .uEntrySelector = ReadUShort(fs)
                .uRangeShift = ReadUShort(fs)
            End With

            If ttOffsetTable.uMajorVersion <> 1 Or ttOffsetTable.uMinorVersion <> 0 Then
                Return Nothing
            End If

            Dim tblDir As New TT_TABLE_DIRECTORY
            Dim found As Boolean = False

            For i As Integer = 0 To ttOffsetTable.uNumOfTables
                With tblDir
                    .Initialize()
                    fs.Read(.szTag, 0, .szTag.Length)
                    .uCheckSum = ReadULong(fs)
                    .uOffset = ReadULong(fs)
                    .uLength = ReadULong(fs)
                End With

                Dim enc As Encoding = Encoding.GetEncoding(encStr)

                Dim s As String = enc.GetString(tblDir.szTag)
                If StrComp(s, "name") = 0 Then
                    found = True
                    Exit For
                End If
            Next

            If Not found Then Return Nothing

            fs.Seek(tblDir.uOffset, SeekOrigin.Begin)
            Dim ttNTHeader As New TT_NAME_TABLE_HEADER
            With ttNTHeader
                .uFSelector = ReadUShort(fs)
                .uNRCount = ReadUShort(fs)
                .uStorageOffset = ReadUShort(fs)
            End With

            Dim ttRecord As New TT_NAME_RECORD

            For j As Integer = 0 To ttNTHeader.uNRCount
                With ttRecord
                    .uPlatformID = ReadUShort(fs)
                    .uEncodingID = ReadUShort(fs)
                    .uLanguageID = ReadUShort(fs)
                    .uNameID = ReadUShort(fs)
                    .uStringLength = ReadUShort(fs)
                    .uStringOffset = ReadUShort(fs)
                End With

                If ttRecord.uNameID > 2 Then Exit For

                Dim nPos As Integer = fs.Position
                fs.Seek(tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset, SeekOrigin.Begin)

                Dim buf(ttRecord.uStringLength - 1) As Byte
                fs.Read(buf, 0, ttRecord.uStringLength)

                Dim enc As Encoding
                If ttRecord.uEncodingID = 3 Or ttRecord.uEncodingID = 1  Then
                    enc = Encoding.BigEndianUnicode
                Else
                    enc = Encoding.UTF8
                End If

                strRet = enc.GetString(buf)
                If ttRecord.uNameID = 1 Then FontName = strRet
                If ttRecord.uNameID = 2 Then FontSubFamily = strRet
                fs.Seek(nPos, SeekOrigin.Begin)
            Next
            Return New InstalledFont(FontName, FontSubFamily, fontFilePath)
        End Using
    End Function
    Public Structure TT_OFFSET_TABLE
        Public uMajorVersion As UShort
        Public uMinorVersion As UShort
        Public uNumOfTables As UShort
        Public uSearchRange As UShort
        Public uEntrySelector As UShort
        Public uRangeShift As UShort
    End Structure
    Public Structure TT_TABLE_DIRECTORY
        Public szTag() As Byte
        Public uCheckSum As UInt32
        Public uOffset As UInt32
        Public uLength As UInt32
        Public Sub Initialize()
            ReDim szTag(3)
        End Sub
    End Structure
    Public Structure TT_NAME_TABLE_HEADER
        Public uFSelector As UShort
        Public uNRCount As UShort
        Public uStorageOffset As UShort
    End Structure
    Public Structure TT_NAME_RECORD
        Public uPlatformID As UShort
        Public uEncodingID As UShort
        Public uLanguageID As UShort
        Public uNameID As UShort
        Public uStringLength As UShort
        Public uStringOffset As UShort
    End Structure
    Private Function ReadChar(ByRef fs As FileStream, ByVal characters As Integer) As UInt16
        Dim s(characters) As String
        Dim buf(CByte(s.Length)) As Byte
        buf = ReadAndSwap(fs, buf.Length)
        Return BitConverter.ToUInt16(buf, 0)
    End Function
    Private Function ReadByte(ByRef fs As FileStream) As UInt16
        Dim buf(10) As Byte
        buf = ReadAndSwap(fs, buf.Length)
        Return BitConverter.ToUInt16(buf, 0)
    End Function
    Private Function ReadUShort(ByRef fs As FileStream) As UInt16
        Dim buf(1) As Byte
        buf = ReadAndSwap(fs, buf.Length)
        Return BitConverter.ToUInt16(buf, 0)
    End Function
    Private Function ReadULong(ByRef fs As FileStream) As UInt32
        Dim buf(3) As Byte
        buf = ReadAndSwap(fs, buf.Length)
        Return BitConverter.ToUInt32(buf, 0)
    End Function
    Private Function ReadAndSwap(ByRef fs As FileStream, ByVal size As Integer) As Byte()
        Dim buf(size - 1) As Byte
        fs.Read(buf, 0, buf.Length)
        Array.Reverse(buf)
        Return buf
    End Function
End Module

这篇关于净列举的WinForms字体样式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆