Dynamically resizing font to fit space while using Graphics.DrawString

farina picture farina · Oct 30, 2013 · Viewed 22.1k times · Source

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?

Answer

saeed picture saeed · Oct 30, 2013

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