净列举的WinForms字体样式? [英] .Net enumerate winforms font styles?
问题描述
我一直在摸索一种方式来列出有效的字体样式使用.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屋!