Search code examples
c#.netgraphicssystem.drawingantialiasing

Why is C# graphics text antialiasing quality so poor with smaller font size?


I'm attempting to use the Bebas font to render text to a Bitmap in C#.

Consider the following code that loads a .png from the filesystem to render overlaying text:

public Bitmap CreateCard(AccumulatedStats player, string template, bool includeGamerpic = false)
    {
        Bitmap imageCache = new Bitmap(template);
        using (Graphics g = Graphics.FromImage(imageCache))
        {
            //AddAvatar(g, player);
            AddGamertag(g, player);
            //AddStats(g, player);
            //AddLogo(g, player);
            AddPrimaryPosition(g, player);
        }
        return imageCache;
    }

The AddGamertag method draws text at size 38 font, and renders correctly:

good text

The AddPrimaryPosition method draws text at size 12 font with unacceptable quality:

        private void AddPrimaryPosition(Graphics g, AccumulatedStats player)
    {
        Brush bgText = new SolidBrush(Color.FromArgb(red: 238, green: 243, blue: 234));
        var centerAlign = new StringFormat() { Alignment = StringAlignment.Center };
        Font bebas = new Font("Bebas", 12);

        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
        g.DrawString($"Lorem Ipsum\nYour Name Here", bebas, bgText, new PointF(601, 221), centerAlign);
        //g.DrawString($"Lorem Ipsum\nYour Name Here", bebas, Brushes.Black, new PointF(843, 221), centerAlign);
    }

bad text

Note that I am using SmoothingMode and TextRenderingHint to specify antialiasing.

Compare that to the quality from Paint.NET: pdn settings

pdn results

I found a question noting similar behaviour, where the accepted answer suggested that the area was not initialized. To remedy this I tried to draw a colored rectangle first before drawing the text, in hopes that the antialiasing would be able to sample from the rectangle behind the text:

        private void AddPrimaryPosition(Graphics g, AccumulatedStats player)
    {
        Brush bgText = new SolidBrush(Color.FromArgb(red: 238, green: 243, blue: 234));
        var centerAlign = new StringFormat() { Alignment = StringAlignment.Center };
        Font bebas = new Font("Bebas", 12);

        // Slight red offset for testing, should be 0
        var islesBlue = new SolidBrush(Color.FromArgb(red: 200, green: 83, blue: 155));
        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        Rectangle rect = new Rectangle(499, 219, 203, 66);
        g.FillRectangle(islesBlue, rect);
        g.DrawRectangle(new Pen(islesBlue), rect);
        

        g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
        g.DrawString($"Lorem Ipsum\nYour Name Here", bebas, bgText, new PointF(601, 221), centerAlign);
        g.DrawString($"Lorem Ipsum\nYour Name Here", bebas, Brushes.Black, new PointF(843, 221), centerAlign);
    }

still bad text

Note that I also rendered the text further to the right, where I have a background that matches the color of the background where AddGamertag draws the larger text.

I changed this method to set SmoothingMode=None and TextRenderingHint=SingleBitPerPixel, which looks different (indicating some antialiasing was happening previously) but also unacceptably poor:

bad text no aa

Why is the antialiasing quality so poor at smaller font sizes? Is there a way to resolve this without resorting to larger text or a different font face?


Solution

  • I tried running the code on a different computer, and the resulting quality was significantly better:

    better version

    The PC I ran this on initially is an old Intel-based Macbook running Windows 10 via Bootcamp, with an Intel Core i2xxx series CPU and Intel HD Graphics 4000.

    The PC I re-ran this on is a Windows 10 desktop with an Intel Core i2500k CPU and an nvidia Geforce GTX970 GPU.

    My guess is that it's a Windows GDI+ issue,as all other variables (source code, source image loaded as Bitmap, etc) have remained the same.

    The explanation for why it may be a GDI+ issue is presented here: Graphics.DrawString vs TextRenderer.DrawText?Which can Deliver Better Quality

    Consider using TextRenderer.DrawText