【问题标题】:PrivateFontCollection.AddMemoryFont producing random errors on Windows Server 2012 R2PrivateFontCollection.AddMemoryFont 在 Windows Server 2012 R2 上产生随机错误
【发布时间】:2014-08-30 14:24:34
【问题描述】:

我有一个 .NET 3.5 应用程序,它使用 PrivateFontCollection.AddMemoryFont 将字体加载到内存中,并使用这些来生成图像。我最近在 Windows Server 2012 R2 上安装了它,它会产生间歇性错误。

用这个方法说明问题:

private Bitmap getImage(byte[] fontFile)
{
    using (PrivateFontCollection fontCollection = new PrivateFontCollection())
    {
        IntPtr fontBuffer = Marshal.AllocCoTaskMem(fontFile.Length);
        Marshal.Copy(fontFile, 0, fontBuffer, fontFile.Length);
        fontCollection.AddMemoryFont(fontBuffer, fontFile.Length);

        Bitmap image = new Bitmap(200, 50);
        using (Font font = new Font(fontCollection.Families[0], 11f, FontStyle.Regular))
        {
            using (Graphics graphics = Graphics.FromImage(image))
            {
                graphics.DrawString(String.Format("{0:HH:mm:ss}", DateTime.Now), font, Brushes.White, new PointF(0f, 0f));
            }
        }
        return image;
    }
}

在 Windows 7 上,这始终有效。在 Windows Server 2012 R2 上,如果使用不止一种字体重复调用它会失败。例如:

getImage(File.ReadAllBytes("c:\\Windows\\Fonts\\Arial.ttf"));

即使调用了数百次也能正常工作,但调用的字体不止一种:

getImage(File.ReadAllBytes("c:\\Windows\\Fonts\\Wingding.ttf"));
getImage(File.ReadAllBytes("c:\\Windows\\Fonts\\Arial.ttf"));

对前几次调用(大约 20 个)有效,但随后会开始产生随机结果(第二次调用有时会返回带有侧翼文本的图像 - 即它混淆了字体)。

我也偶尔(很少)在 DrawString 调用中收到“GDI+ 中发生一般错误”。

在 Windows 7 上不会发生这些错误。

我尝试了各种清理方法,但均未成功。

作为一种解决方法,我尝试将字体文件写入磁盘,然后使用 AddFontFile 加载,但是(在 Windows 2012 R2 上)字体文件在整个过程中都会被锁定,因此无法删除。这使得这个选项不可接受。

任何有关使 AddMemoryFont 持续工作或让 AddFontFile 解锁文件的帮助,我们将不胜感激。

【问题讨论】:

  • 标准 GDI+ 丢失,处理字体实际上并不会破坏它。它被放回缓存中,假设它会再次被使用。一个重要的性能优化,创建字体非常昂贵。当你破坏它们的家时,私有字体的结局很糟糕,字体将使用释放的内存。产生令人眼花缭乱的结果,包括硬崩溃。您需要保留集合以及 IntPtr。
  • 您找到解决方法了吗?我在 Windows Server 2012R2 上也遇到了同样的问题。该代码在 Windows Server 2003 上运行良好。
  • @HansPassant 我遇到了一个测试套件,即使没有处理任何 Font 或 FontFamily,GDI+ 在调用 AddMemoryFont() 时也会将错误的字体系列添加到集合中。

标签: .net fonts gdi+ windows-server-2012-r2 privatefontcollection


【解决方案1】:

一个迟到的答案,但也许其他人会对此感到满意: 我遇到了完全相同的问题,经过数小时的反复试验,我发现一个可行的解决方案是将字体(数据库中的字节数组)保存到本地文件并使用 addFontFile 方法加载文件。

所有问题都解决了。不是一个理想的解决方案,而是一个可行的解决方案。

var path = Path.Combine(TemporaryFontPath, customFont.FontFileName);
if (!Directory.Exists(Path.GetDirectoryName(path)))
    Directory.CreateDirectory(Path.GetDirectoryName(path));
if(!File.Exists(path))
    File.WriteAllBytes(path, customFont.FontBytes);

using (var pvc = new PrivateFontCollection())
{
    pvc.AddFontFile(path);
    return pvc.Families.FirstOrDefault();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多