Получить 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);
}