net - personalizar columnas datagridview c#
.Net enumera los estilos de fuente winforms? (5)
¿Qué le parece usar FontFamily.IsStyleAvailable para verificar si el estilo de fuente está disponible o no para cada familia de fuentes? Puede verificar los estilos de fuente interesados (si están disponibles) y luego enumerar los estilos admitidos.
He estado buscando una forma de listar los estilos de fuente válidos para una fuente determinada usando .Net framework (incluso si tengo que pinvoke gdi32 o alguna otra API) ya que no todas las fuentes caen dentro de los valores enum de System.Drawing.FontStyle (Negrita, Cursiva, Regular, Strikeout, Subrayado). Un ejemplo perfecto de una fuente que no encaja en la factura es Segoe UI, que es una fuente TrueType de Microsoft, con estilos de fuente de: Regular, Semibold, Light, Bold, Italic y BoldItalic. Otro ejemplo es Arial que tiene: Regular, Estrecho, Cursiva, Negrita, Negrita Cursiva, Estrecha Negrita, Negrita negrita cursiva y Estrecha cursiva.
En Windows 7 (probablemente también, pero no tengo una máquina para verificar) cuando abres el explorador y buscas% SystemRoot% / Fonts, verás una columna llamada "Estilo de fuente" que enumera todos los estilos disponibles para cada fuente, lo que me dice que definitivamente hay una forma de hacerlo, al menos a través de llamadas API.
En última instancia, estoy buscando enumerar la lista de FontFamily y luego enumerar cada estilo de fuente para cada familia. A continuación se muestra un código de muestra para enumerar todas las familias de fuentes, si alguien pudiera proporcionar ayuda para enumerar los estilos de fuente disponibles para cada familia, se lo agradecería. Si estoy haciendo esto de la manera incorrecta, definitivamente estoy abierto a sugerencias.
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());
*/
}
Bien, esto va a ser un montón de código a continuación. En primer lugar, se debe a las estructuras TTF y Endianess de los archivos TTF. El código no es originalmente mío, proviene de algunas fuentes que he transferido a VB.NET y he cambiado algunas cosas. Consulte esta página para obtener una versión de C ++ que obtiene el nombre de la fuente.
Este código lee el registro de las fuentes instaladas (ya sea en% windir% / fonts u otro), los filtros solo obtienen los que tienen la extensión .ttf (por ejemplo, .fon y .ttc se ignoran) y luego pasa estas rutas de archivos de fuentes a una rutina, GetFontDetails
, que se lee y obtiene el nombre de la fuente (uNameID # 1) y Font Sub Family (aka Style, uNameID # 2). Si está interesado en obtener más propiedades que esas, vaya al nombre - Naming Table en el sitio web de Typography de Microsoft y busque en su navegador ID de nombre . A continuación, inicia el Nombre de la fuente, la Subfamilia de fuentes y la Ruta de la fuente a la ventana de la Consola.
Cree una nueva aplicación de consola VB.NET y pegue lo siguiente en el código Module1 y presione F5 .
Sin más preámbulos:
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
Gracias Otaku y Todos ... Tomaron el código de Otaku y se portaron a c # para cualquiera que esté interesado ... pero no llegaron a la actualización de OTF. Los principales cambios fueron solo los ajustes de matriz de bytes (matrices de pads VB), expresiones lambda y los cambios de sintaxis habituales ...
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.Win32;
namespace InstalledFontsInSystem
{
class InstalledFont
{
#region InstalledFont Parameters
string _fontName = string.Empty;
string _fontSubFamily = string.Empty;
string _fontPath = string.Empty;
#endregion
#region InstalledFont Constructor
public InstalledFont(string fontName, string fontSubFamily, string fontPath)
{
_fontName = fontName;
_fontSubFamily = fontSubFamily;
_fontPath = fontPath;
}
#endregion
#region InstalledFont Properties
public string FontName { get { return _fontName; } set { _fontName = value; } }
public string FontSubFamily { get { return _fontSubFamily; } set { _fontSubFamily = value; } }
public string FontPath { get { return _fontPath; } set { _fontPath = value; } }
#endregion
}
class Program
{
static void Main(string[] args)
{
var allInstalledFonts = from e in Registry.LocalMachine.OpenSubKey("Software//Microsoft//Windows NT//CurrentVersion//Fonts", false).GetValueNames()
select Registry.LocalMachine.OpenSubKey("Software//Microsoft//Windows NT//CurrentVersion//Fonts").GetValue(e);
var ttfFonts = from e in allInstalledFonts.Where(e => (e.ToString().EndsWith(".ttf") || e.ToString().EndsWith(".otf"))) select e;
var ttfFontsPaths = from e in ttfFonts.Select(e => (Path.GetPathRoot(e.ToString()) == "") ? Environment.GetFolderPath(Environment.SpecialFolder.Fonts) + "//" + e.ToString() : e.ToString()) select e;
var fonts = from e in ttfFontsPaths.Select(e => GetFontDetails(e.ToString())) select e;
foreach (InstalledFont f in fonts)
{
if(f != null)
Console.WriteLine("Name: " + f.FontName + ", SubFamily: " + f.FontSubFamily + ", Path: " + f.FontPath);
}
Console.ReadLine();
}
static public InstalledFont GetFontDetails(string fontFilePath)
{
string FontName = string.Empty;
string FontSubFamily = string.Empty;
string encStr = "UTF-8";
string strRet = string.Empty;
using (FileStream fs = new FileStream(fontFilePath, FileMode.Open, FileAccess.Read))
{
TT_OFFSET_TABLE ttOffsetTable = new TT_OFFSET_TABLE()
{
uMajorVersion = ReadUShort(fs),
uMinorVersion = ReadUShort(fs),
uNumOfTables = ReadUShort(fs),
uSearchRange = ReadUShort(fs),
uEntrySelector = ReadUShort(fs),
uRangeShift = ReadUShort(fs),
};
if (ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0)
{
return null;
}
TT_TABLE_DIRECTORY tblDir = new TT_TABLE_DIRECTORY();
bool found = false;
for (int i = 0; i <= ttOffsetTable.uNumOfTables; i++)
{
tblDir = new TT_TABLE_DIRECTORY();
tblDir.Initialize();
fs.Read(tblDir.szTag, 0, tblDir.szTag.Length);
tblDir.uCheckSum = ReadULong(fs);
tblDir.uOffset = ReadULong(fs);
tblDir.uLength = ReadULong(fs);
Encoding enc = Encoding.GetEncoding(encStr);
string s = enc.GetString(tblDir.szTag);
if (s.CompareTo("name") == 0)
{
found = true;
break;
}
}
if (!found) return null;
fs.Seek(tblDir.uOffset, SeekOrigin.Begin);
TT_NAME_TABLE_HEADER ttNTHeader = new TT_NAME_TABLE_HEADER
{
uFSelector = ReadUShort(fs),
uNRCount = ReadUShort(fs),
uStorageOffset = ReadUShort(fs)
};
TT_NAME_RECORD ttRecord = new TT_NAME_RECORD();
for (int j = 0; j <= ttNTHeader.uNRCount; j++)
{
ttRecord = new TT_NAME_RECORD()
{
uPlatformID = ReadUShort(fs),
uEncodingID = ReadUShort(fs),
uLanguageID = ReadUShort(fs),
uNameID = ReadUShort(fs),
uStringLength = ReadUShort(fs),
uStringOffset = ReadUShort(fs)
};
if (ttRecord.uNameID > 2) { break; }
long nPos = fs.Position;
fs.Seek(tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset, SeekOrigin.Begin);
byte[] buf = new byte[ttRecord.uStringLength];
fs.Read(buf, 0, ttRecord.uStringLength);
Encoding enc;
if (ttRecord.uEncodingID == 3 || ttRecord.uEncodingID == 1)
{
enc = Encoding.BigEndianUnicode;
}
else
{
enc = Encoding.UTF8;
}
strRet = enc.GetString(buf);
if (ttRecord.uNameID == 1) { FontName = strRet; }
if (ttRecord.uNameID == 2) { FontSubFamily = strRet; }
fs.Seek(nPos, SeekOrigin.Begin);
}
return new InstalledFont(FontName, FontSubFamily, fontFilePath);
}
}
public struct TT_OFFSET_TABLE
{
public ushort uMajorVersion;
public ushort uMinorVersion;
public ushort uNumOfTables;
public ushort uSearchRange;
public ushort uEntrySelector;
public ushort uRangeShift;
}
public struct TT_TABLE_DIRECTORY
{
public byte[] szTag;
public UInt32 uCheckSum;
public UInt32 uOffset;
public UInt32 uLength;
public void Initialize()
{
szTag = new byte[4];
}
}
public struct TT_NAME_TABLE_HEADER
{
public ushort uFSelector;
public ushort uNRCount;
public ushort uStorageOffset;
}
public struct TT_NAME_RECORD
{
public ushort uPlatformID;
public ushort uEncodingID;
public ushort uLanguageID;
public ushort uNameID;
public ushort uStringLength;
public ushort uStringOffset;
}
static private UInt16 ReadChar(FileStream fs, int characters)
{
string[] s = new string[characters];
byte[] buf = new byte[Convert.ToByte(s.Length)];
buf = ReadAndSwap(fs, buf.Length);
return BitConverter.ToUInt16(buf, 0);
}
static private UInt16 ReadByte(FileStream fs)
{
byte[] buf = new byte[11];
buf = ReadAndSwap(fs, buf.Length);
return BitConverter.ToUInt16(buf, 0);
}
static private UInt16 ReadUShort(FileStream fs)
{
byte[] buf = new byte[2];
buf = ReadAndSwap(fs, buf.Length);
return BitConverter.ToUInt16(buf, 0);
}
static private UInt32 ReadULong(FileStream fs)
{
byte[] buf = new byte[4];
buf = ReadAndSwap(fs, buf.Length);
return BitConverter.ToUInt32(buf, 0);
}
static private byte[] ReadAndSwap(FileStream fs, int size)
{
byte[] buf = new byte[size];
fs.Read(buf, 0, buf.Length);
Array.Reverse(buf);
return buf;
}
}
}
HTH Dave
Dave, comentando esta versión de verificación:
if (ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0)
{
return null;
}
hice el truco para mí, puedo obtener nombres de fuentes .otf también ahora ...
También se agregó un par de ToLower (s)
IEnumerable<object> ttfFonts = from e in allInstalledFonts.Where(e => (e.ToString().ToLower().EndsWith(".ttf") || e.ToString().ToLower().EndsWith(".otf"))) select e;
Algunas de mis fuentes instaladas donde todo en mayúsculas causa la cláusula == no encuentra nada debido a la comparación ttf == TTF.
Espero que ayude a alguien!
Me encontré en el mismo barco que todos aquí. ¡Todos queremos ese comportamiento de agrupación de diálogo de fuente nativa mágica, y no hay API para soportarlo! Lamentablemente, la respuesta actual hizo lo mismo que GDI + y System.Drawing: aislar Segoe UI Semibold
o Arial Black
en familias de una sola fuente y perder la conexión con Segoe UI
y Arial
. Supongo que eso lo convierte en la oveja negra de la familia Arial ...
Comencé un proyecto de código abierto para resolver esto y el análisis OTF / TTC y para proporcionar una buena API. Maneja todas las cajas de esquina que arrojé. Siéntase libre de copiar o modificar el código. https://github.com/jnm2/TypographicFonts
Su ejemplo de código se convierte en:
foreach (var ff in TypographicFontFamily.InstalledFamilies)
{
Console.WriteLine(ff.Name);
foreach (var font in ff.Fonts)
{
Console.WriteLine(f.Subfamily);
// var gdiPlusFont = new Font(f.Name, 16);
}
}
Si lo que realmente te interesa es aplicar un estilo a un objeto de fuente existente:
var semiboldFont = new Font("Segoe UI", 9).With(TypographicFontWeight.Semibold);
Console.WriteLine(semiboldFont.Name); // "Segoe UI Semibold"
Usted no está restringido a las fuentes instaladas, tampoco. Para analizar las fuentes de un archivo de fuente, use TypographicFont.FromFile
.
Gracias a Todd Main por ser pionero.