Search code examples
c#.netfontssystem.drawing

Dynamically resizing font to fit space while using Graphics.DrawString


Does anyone have a tip whereas you could dynamically resize a font to fit a specific area? For example, I have an 800x110 rectangle and I want to fill it with the max size font that would support the entire string I'm trying to display.

Bitmap bitmap = new Bitmap(800, 110);

using (Graphics graphics = Graphics.FromImage(bitmap))
using (Font font1 = new Font("Arial", 120, FontStyle.Regular, GraphicsUnit.Pixel))
{
    Rectangle rect1 = new Rectangle(0, 0, 800, 110);

    StringFormat stringFormat = new StringFormat();
    stringFormat.Alignment = StringAlignment.Center;
    stringFormat.LineAlignment = StringAlignment.Center;

    graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
    graphics.DrawString("Billy Reallylonglastnameinstein", font1, Brushes.Red, rect1, stringFormat);
} 

bitmap.Save(Server.MapPath("~/Fonts/" + System.Guid.NewGuid() + ".png"));

Obviously that whole name won't render in the space provided at the large font size. There has to be a simple way to do this?


Solution

  • You should do a scale transform on Font.Size the following function is an example of doing that but you can improve it to apply better results.

    Here is FindFont function which get a room and a text with prefered size and gives you a font in which you can set that whole text fits the room!

    // This function checks the room size and your text and appropriate font
    //  for your text to fit in room
    // PreferedFont is the Font that you wish to apply
    // Room is your space in which your text should be in.
    // LongString is the string which it's bounds is more than room bounds.
    private Font FindFont(
       System.Drawing.Graphics g,
       string longString,
       Size Room,
       Font PreferedFont
    ) {
       // you should perform some scale functions!!!
       SizeF RealSize = g.MeasureString(longString, PreferedFont);
       float HeightScaleRatio = Room.Height / RealSize.Height;
       float WidthScaleRatio = Room.Width / RealSize.Width;
    
       float ScaleRatio = (HeightScaleRatio < WidthScaleRatio)
          ? ScaleRatio = HeightScaleRatio
          : ScaleRatio = WidthScaleRatio;
    
       float ScaleFontSize = PreferedFont.Size * ScaleRatio;
    
       return new Font(PreferedFont.FontFamily, ScaleFontSize);
    }
    

    For your question you can call it like the following code:

    Bitmap bitmap = new Bitmap(800, 110);
    
    using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmap))
    using (Font font1 = new Font("Arial", 120, FontStyle.Regular, GraphicsUnit.Pixel))
    {
       Rectangle rect1 = new Rectangle(0, 0, 800, 110);
    
       StringFormat stringFormat = new StringFormat();
       stringFormat.Alignment = StringAlignment.Center;
       stringFormat.LineAlignment = StringAlignment.Center;
       graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
    
       Font goodFont = FindFont(graphics, "Billy Reallylonglastnameinstein", rect1.Size, font1);
    
       graphics.DrawString(
          "Billy Reallylonglastnameinstein",
          goodFont,
          Brushes.Red,
          rect1,
          stringFormat
       );
    }