делает свою работу

мы хотели бы использоватьttf шрифты как встроенные ресурсы без копирования или установки их в систему и без их записи на диск. Без проблем с утечкой памяти.

Ни одно из решений не описано в:

Как включить внешний шрифт в приложение WPF без его установки

могут использоваться в этом сценарии из-за утечки памяти WPF вокруг этого:

Утечка памяти в WPF TextBlock при использовании шрифта

Установка шрифтов из памяти и только процесс возможны в GDI черезAddFontMemResourceEx, Так как при этом устанавливается шрифт для процесса, он должен работать и для WPF, но, похоже, существуют проблемы вокругFontFamily что мы получаем после установки шрифта черезAddFontMemResourceEx, Например.:

var font = new FontFamily("Roboto");

Это работает в том, что это не дает никаких ошибок, но шрифт фактически не изменен, некоторые межстрочные интервалы и другие метрики изменены, но шрифт выглядит в точности какSegoe UI по какой-то причине.

Тогда возникает вопрос: а как можно использовать шрифты, установленные сAddFontMemResourceEx в WPF?

PS: здесь код P / Invoke:

const string GdiDllName = "gdi32";
[DllImport(GdiDllName, ExactSpelling= true)]
private static extern IntPtr AddFontMemResourceEx(byte[] pbFont, int cbFont, IntPtr pdv, out uint pcFonts);

public static void AddFontMemResourceEx(string fontResourceName, byte[] bytes, Action<string> log)
{
    var handle = AddFontMemResourceEx(bytes, bytes.Length, IntPtr.Zero, out uint fontCount);
    if (handle == IntPtr.Zero)
    {
        log?.Invoke($"Font install failed for '{fontResourceName}'");
    }
    else
    {
        var message = $"Font installed '{fontResourceName}' with font count '{fontCount}'";
        log?.Invoke(message);
    }
}

Этот код преуспевает с сообщениями журнала как:

Font installed 'Roboto-Regular.ttf' with font count '1'

Код поддержки для загрузки встроенного ресурса в виде байтового массива:

public static byte[] ReadResourceByteArray(Assembly assembly, string resourceName)
{
    using (var stream = assembly.GetManifestResourceStream(resourceName))
    {
        var bytes = new byte[stream.Length];
        int read = 0;
        while (read < bytes.Length)
        {
            read += stream.Read(bytes, read, bytes.Length - read);
        }
        if (read != bytes.Length)
        {
            throw new ArgumentException(
                $"Resource '{resourceName}' has unexpected length " +
                $"'{read}' expected '{bytes.Length}'");
        }
        return bytes;
    }
}

Это означает, что установка встроенных шрифтов может быть выполнена как, сassembly будучи сборкой, содержащей ресурсы встроенного шрифта иEMBEDDEDFONTNAMESPACE быть пространством имен встроенных ресурсов, напримерSomeProject.Fonts:

var resourceNames = assembly.GetManifestResourceNames();

string Prefix = "EMBEDDEDFONTNAMESPACE" + ".";
var fontFileNameToResourceName = resourceNames.Where(n => n.StartsWith(Prefix))
    .ToDictionary(n => n.Replace(Prefix, string.Empty), n => n);

var fontFileNameToBytes = fontFileNameToResourceName
    .ToDictionary(p => p.Key, p => ReadResourceByteArray(assembly, p.Value));

foreach (var fileNameBytes in fontFileNameToBytes)
{
    AddFontMemResourceEx(fileNameBytes.Key, fileNameBytes.Value, log);
}

Ответы на вопрос(0)

Ваш ответ на вопрос