Получить System.Drawing.Font из System.Windows.Media.FontFamily

Есть приложение на WPF, которое отображает график в реальном времени. В целях производительности отрисовка сделана с помощью System.Windows.Media.Imaging.WriteableBitmap и System.Drawing.Graphics. Также нужно отрисовывать текст, используя сторонний шрифт. В WPF для работы с шрифтами используется System.Windows.Media.FontFamily. FontFamily задается в отдельной сборке темы, там же хранятся и сами шрифты. Для отрисовки текста мне нужен объект System.Drawing.Font. Есть способ как получить Font из FontFamily?

System.Drawing.Font можно получить из System.Drawing.Text.PrivateFontCollection, но для этого нужно передать в нее путь к файлу шрифта. Файлы шрифта пакуются в отдельную сборку с темой, можно их оттуда достать и передать в PrivateFontCollection или нужно их добавлять как отдельные файлы?


Ответы (1 шт):

Автор решения: Виталий Ефимов

Напрямую получить System.Drawing.FontFamily, из System.Windows.Media.FontFamily не получилось. Но получилось извлечь файл шрифта из сборки с темой, и используя его, создать System.Drawing.Font. Правда получение потока с файлом шрифта немного сложнее, чем казалось изначально. Указатель на поток шрифта можно получить как через Marshal, так и через unsafe код. Важно! Нужно хранить ссылку на PrivateFontCollection, пока в приложении используется шрифт, иначе получим исключение при попытке доступа к шрифту.

private static PrivateFontCollection pfc;

    public static void Initialize()
    {
        var assemblyName = (string)Application.Current.FindResource("assemblyName_Key");
        var fontName = (string)Application.Current.FindResource("fontName_Key");
        var fontSize = (float)Application.Current.FindResource("fontSize_Key");

        var assembly = AppDomain.CurrentDomain.GetAssemblies().First(x => x.GetName().Name == assemblyName);
        var strResources = assembly.GetName().Name + ".g.resources";
        var rStream = assembly.GetManifestResourceStream(strResources);
        var resourceReader = new System.Resources.ResourceReader(rStream);
        
        var fontStream = (Stream)resourceReader.OfType<System.Collections.DictionaryEntry>()
            .First(x => x.Key.ToString().IsOrdinalEqualsIgnoreCase(fontName)).Value;
        byte[] fontBytes = new byte[fontStream.Length];
        fontStream.Read(fontBytes, 0, (int)fontStream.Length);
        fontStream.Close();

        pfc = new PrivateFontCollection();

        var fontData = Marshal.AllocCoTaskMem(fontBytes.Length);
        Marshal.Copy(fontBytes, 0, fontData, fontBytes.Length);
        
        pfc.AddMemoryFont(fontData, fontBytes.Length);
        Marshal.FreeCoTaskMem(fontData);

        //unsafe
        //{
        //    fixed (byte* pFontData = fontBytes)
        //    {
        //        pfc.AddMemoryFont((IntPtr)pFontData, fontBytes.Length);
        //    }
        //}

        Context.TextFont = new System.Drawing.Font(pfc.Families[0], fontSize);
    }
→ Ссылка