9
votes

.Net énumérer des styles de police Winforms?

Je cherche un moyen de répertorier les styles de police valides pour une police donnée à l'aide du cadre .NET (même si je dois pinvoke gdi32 ou une autre API), car toutes les polices ne sont pas toutes les polices tombent dans le système. Valeurs de FonteStyle Enum (gras, italique, régulier, chuteout, souligné). SEGOE UI est un exemple parfait de police qui ne correspond pas à la facture est SEGOE UI, qui est une police Microsoft TrueType, avec des styles de police de: régulier, semi-jibold, léger, gras, italique et bolitaux. Un autre exemple est l'ARIAL qui a: régulier, étroit, italique, gras, italique gras, gras gras, alternatif étroit italique et étroit italique.

dans Windows 7 (probablement Vista aussi, mais je n'ai pas de machine à Vérifiez) Lorsque vous ouvrez Explorer et parcourez% Systemroot% \ Polices, vous verrez une colonne appelée "style de police" qui énumère tous les styles disponibles pour chaque police, ce qui me dit qu'il y a définitivement un moyen de faire cela, à Le moins via les appels API. P>

En fin de compte, je cherche à énumérer la liste FontNamily, puis énumérez chaque style de police pour chaque famille. Vous trouverez ci-dessous un exemple de code pour répertorier toutes les familles de polices, si quelqu'un pouvait fournir une assistance pour la liste des styles de police disponibles pour chaque famille, je l'apprécierais. Si je vais à ce sujet, je suis absolument ouvert aux suggestions. P>

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());
    */
}


3 commentaires

Une chose à noter: Un autre exemple qui montre ce que je veux faire serait simplement d'ouvrir l'outil de texte dans Photoshop, qui a une liste déroulante distincte répertoriant tous les styles de police. La façon dont Mspaint le fait là où elle sépare les familles spéciales (SEGOE UI Light, SEGOE UI Semibold) serait également acceptable, mais ce n'est pas la manière dont l'installation installefontCollection semble fonctionner, de sorte que cette manière peut donc être effectuée via des appels d'API entièrement .. .


J'en ai Ça Ça Ça ... la façon dont Mspaint est-il réellement de savoir comment mon exemple de code fonctionne. C'est pas en fait ce que je cherche. Désolé ... je ne pense pas à 100% clairement o_o


J'ai besoin de finaliser une solution sur cette même chose pour un moment maintenant - votre question me motive de le faire. Ma solution n'utilise pas Enumfontfamiliesex - plutôt, il lit le registre, puis bouclent toutes les polices pour les trouver et leurs informations, incluez le style (c'est-à-dire une sous-famille). Je fais cela parce que j'ai besoin d'un accès direct à la police physique juste après avoir trouvé celui que j'ai besoin pour l'intégrer dans mon programme. Oh, et je le fais dans vb.net au lieu de c #. Une fois que je l'ai, je posterai le code.


5 Réponses :



6
votes

D'accord, cela va être beaucoup de code ci-dessous. Principalement, c'est à cause des structures TTF et de l'endianesse des fichiers TTF. Le code n'est pas à l'origine à l'origine, il provient de quelques sources que j'ai portées à VB.net et a changé quelques éléments. Voir Cette page pour une version C ++ obtient le nom de police.

Ce code lit dans le registre des polices installées (que ce soit dans% windir% \ polices ou ailleurs), les filtres à obtenir uniquement avec l'extension .ttf (par exemple, etc.tc sont ignorés), puis il transmet ces chemins de fichiers de police à Une routine, getfontDétails , qui se lit et obtient le nom de police (non référencé n ° 1) et la sous-famille de polices (style AKA, non référencé # 2). Si vous souhaitez obtenir plus de propriétés que celles, allez à Nom - Table de nommage Sur le site Web de la typographie de Microsoft et recherchez dans votre navigateur pour Nom IDs . Il démarre ensuite le nom de police, la sous-famille de polices et le chemin de police vers la fenêtre de la console.

Créer une nouvelle application de console VB.NET et coller le code ci-dessous dans le code de Module1 et appuyez sur F5 .

sans autre ado: xxx


8 commentaires

C'est exactement ce que je cherchais ... Bien que ce soit un peu décevant, il n'y a aucun moyen de le faire dans les appels API :( Merci!


+1. Je l'ai cherché depuis longtemps. Décevant qu'il ne peut pas lire les fichiers TTC ou OTF.


@Chickendinner: J'ai modifié le code de sorte qu'il puisse également lire des fichiers OTF. Je ne sais toujours pas quoi faire à propos des fichiers TTC cependant. Si je le découvre, je vais mettre à jour le code ici.


La fonction sans papiers GetFontresourceInfo Cela semble également intéressant.


J'ai une version de ceci en C # qui gère TTC ainsi que TTF et OTF. En outre, le code actuel n'accomcit pas tout à fait l'objectif. Il traite Segoe Ui Semibold en tant que police séparée de Segoe UI et Arial Black comme distinct de Arial. En effet, les ID de noms 1 et 2 ( Police Nom de la famille) sont utilisés à la place des IDS 16 et 17 ( Typographique Nom de famille). Voir la spécific . C'est aussi légèrement plus efficace. Si quelqu'un est intéressé par la source de travail pour cela, je vais le faire pour vous.


@ jnm2, ce serait génial si vous pouviez poster le code sur Git ou Dropbox pour que les gens puissent accéder. Ce monde TTF / OTF / TTC est difficile - chaque peu nous aide tous.


Voici. github.com/jnm2/typographicFont J'ai l'intention de le maintenir, alors n'hésitez pas à commencer un problème pour un problème Demande de bug ou de fonctionnalité.


J'avais un coup d'œil rapide - il a fière allure, surtout dans la capacité de lire TTC. Merci d'avoir posté cela sur Git!



3
votes

Merci Otaku et tout ... A pris le code d'Otaku et porté à C # pour tout ce qui est intéressé ... mais n'a pas reçu la mise à jour de la FTO. Les principaux changements n'étaient que des réglages de réseau d'octets (tableaux de patins VB), des expressions Lambda et de la syntaxe habituelle ...

    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;
        }
    }
}


0 commentaires

0
votes

Dave, commentant cette version Vérification:

    IEnumerable<object> ttfFonts = from e in allInstalledFonts.Where(e => (e.ToString().ToLower().EndsWith(".ttf") || e.ToString().ToLower().EndsWith(".otf"))) select e;


0 commentaires

1
votes

Je me suis retrouvé dans le même bateau que tout le monde ici. Nous voulons tous que la boîte de dialogue magique de la boîte de dialogue de la police natale, et il n'y a pas d'API pour le supporter! Malheureusement, la réponse actuelle a fait la même chose que GDI + et System.Drawing faire: isoler SEGOE UI Semibold ou Arial Black dans des familles à première police de leur propre et perdent la connexion avec Segoe UI et Arial . Je suppose que cela en fait le mouton noir de la famille Ariale ...

J'ai lancé un projet open source pour résoudre ce problème et l'analyse de l'OTF / TTC et de fournir une API agréable. Il gère tous les cas d'angle que j'ai jetés. N'hésitez pas à copier ou à modifier le code. https://github.com/jnm2/typographicFont

Votre exemple de code devient : xxx

Si ce que vous êtes vraiment intéressé, c'est l'application d'un style à un objet de police existant: xxx

vous ne sont pas limités aux polices installées non plus. Pour analyser les polices d'un fichier de polices, utilisez typographiquefont.fromfile .

merci à TODD Main pour pionnier.


0 commentaires