tcn*_*lan 7 .net c# fonts styles enumeration
我一直在寻找一种方法来列出使用.Net框架的给定字体的有效字体样式(即使我必须使用gdi32或其他一些API),因为并非所有字体都属于System.Drawing.FontStyle枚举值(粗体,斜体,常规,罢工,下划线).Segoe UI是一种TrueType Microsoft字体,字体样式为:Regular,Semibold,Light,Bold,Italic和BoldItalic,这是一个不符合要求的字体的完美示例.另一个例子是Arial,它具有:Regular,Narrow,Italic,Bold,Bold Italic,Narrow Bold,Narrow Bold Italic和Narrow Italic.
在Windows 7中(可能也是vista,但我没有要检查的机器)当您打开资源管理器并浏览到%SystemRoot%\ Fonts时,您将看到一个名为"字体样式"的列,其中列出了所有可用的样式对于每种字体,它告诉我有一种方法可以做到这一点,至少通过API调用.
最后,我希望枚举FontFamily列表,然后列出每个系列的每种字体样式.下面列出了所有字体系列的示例代码,如果有人可以提供帮助列出每个家庭可用的字体样式,我将不胜感激.如果我以错误的方式解决这个问题,我绝对愿意接受建议.
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());
*/
}
Run Code Online (Sandbox Code Playgroud)
好的,这将是下面的很多代码.主要是因为TTF文件的TTF结构和Endianess.代码本来不是我的,它来自一些我已经移植到VB.NET并改变了一些东西的来源.有关获取字体名称的C++版本,请参阅此页面.
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
Run Code Online (Sandbox Code Playgroud)