Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PrivateFontCollection.AddMemoryFont producing random errors on Windows Server 2012 R2

I have a .NET 3.5 application that loads fonts into memory using PrivateFontCollection.AddMemoryFont and uses these to produce images. I have recently installed this on Windows Server 2012 R2 and it is producing intermittent errors.

The problem is illustrated by this method:

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

On Windows 7 this works consistently. On Windows Server 2012 R2 it fails if called repeatedly using more than one font. For example:

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

works even if called hundreds of times, but calling with more than one font:

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

will work for the first several calls (20 or so) but will then start to produce random results (the second call will sometimes return an image with text in wingdings - ie it's mixing up the fonts).

I also occasionally (rarely) get "A generic error occurred in GDI+" on the DrawString call.

None of these errors occur on Windows 7.

I have tried various options to clean up without any success.

As a workaround I have tried writing the font file to disk, then loading with AddFontFile, but (on Windows 2012 R2) the font file gets locked for the life of the process so cannot be deleted. This makes this option unacceptable.

Any help with either getting AddMemoryFont to work consistently, or getting AddFontFile to unlock the file, would be hugely appreciated.

like image 581
dan2132 Avatar asked Aug 30 '14 14:08

dan2132


1 Answers

A late answer, but maybe somebody else will be happy with it: I had exactly the same problems and after hours of trial and error i found out that a working solution for me was saving the font (bytearray from database) to a local file and loaded the file with the addFontFile method.

All problems were gone. Not an ideal solution, but a working one.

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();
}
like image 62
Rubinho G. Avatar answered Oct 19 '22 16:10

Rubinho G.