【问题标题】:Auto Resize Font to fit rectangle自动调整字体大小以适合矩形
【发布时间】:2013-03-22 13:35:40
【问题描述】:

如何在 .NET 4.5 / C# 中创建具有自适应大小以适合指定矩形的字体?

我有一个基于字符串长度的调整大小,字符串越长,字体越小,但效果不是很好,如果字符串太长,文本会变得非常小。这种方法的问题是,如果我改变矩形大小,所有的字体大小都不好了。

【问题讨论】:

  • 您尝试过什么吗?请阅读FAQHow to Ask
  • 现在我有一个基于字符串长度的resize,字符串越长,fontsize越小,但是效果不是很好。

标签: c# .net fonts


【解决方案1】:

已经有一段时间了,但我遇到了这个问题。 MSDN 提供了一个带有 GetAdjustedFont 方法的示例来帮助完成此过程:

(无耻地从https://msdn.microsoft.com/en-us/library/bb986765.aspx窃取)

public Font GetAdjustedFont(Graphics g, string graphicString, Font originalFont, int containerWidth, int maxFontSize, int minFontSize, bool smallestOnFail)
{
   Font testFont = null;
   // We utilize MeasureString which we get via a control instance           
   for (int adjustedSize = maxFontSize; adjustedSize >= minFontSize; adjustedSize--)
   {
      testFont = new Font(originalFont.Name, adjustedSize, originalFont.Style);

      // Test the string with the new size
      SizeF adjustedSizeNew = g.MeasureString(graphicString, testFont);

      if (containerWidth > Convert.ToInt32(adjustedSizeNew.Width))
      {
         // Good font, return it
         return testFont;
      }
   }

   // If you get here there was no fontsize that worked
   // return minimumSize or original?
   if (smallestOnFail)
   {
      return testFont;
   }
   else
   {
      return originalFont;
   }
}

【讨论】:

    【解决方案2】:

    使用Graphics.MeasureString,您可以测量字符串的大小,从而计算出您需要的大小。

    来自 MSDN 的示例

    private void MeasureStringMin(PaintEventArgs e)
    {
    
        // Set up string. 
        string measureString = "Measure String";
        Font stringFont = new Font("Arial", 16);
    
        // Measure string.
        SizeF stringSize = new SizeF();
        stringSize = e.Graphics.MeasureString(measureString, stringFont);
    
        // Draw rectangle representing size of string.
        e.Graphics.DrawRectangle(new Pen(Color.Red, 1), 0.0F, 0.0F, stringSize.Width, stringSize.Height);
    
        // Draw string to screen.
        e.Graphics.DrawString(measureString, stringFont, Brushes.Black, new PointF(0, 0));
    }
    

    【讨论】:

    • .. 您将其用作基础,因为将有必要进行一些迭代(基于简单的规则,例如减少 0.1 或更复杂的规则,例如,除以先前大小的一半,如果合适 - 尝试增加等),也许还有一些逻辑可以在MeasureStringMin之前将文本拆分成行(如果文本可以显示在多行中)。
    【解决方案3】:

    您可以使用任何字体大小(例如 16)测量字符串宽度,然后您可以像这样计算所需的字体大小:

    fontSize = (previouslyMeasuredFontSize * targetWidthOfString) / previouslyMeasuredStringWidth;
    

    【讨论】:

      【解决方案4】:

      我也需要类似的东西。我创建了一些代码来满足在具有多个自动字体大小选项的已定义矩形内绘制文本的需求(请参阅 DrawMethod 枚举)。它还支持带和不带自动字体大小的自动变形。我的解决方案受到上述答案的启发。 请务必添加 WindowsBase 和 PresentationCore 程序集。

      DrawTextToBitmap.cs

      using System;
      using System.Collections.Generic;
      using System.Drawing;
      using System.Drawing.Drawing2D;
      using System.Drawing.Text;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      
      namespace ReportPrepare
      {
          class TextDrawing
          {
              public enum DrawMethod
              {
                  AutosizeAccordingToText, // create the smallest bitmap needed to draw the text without word warp
                  AutoFitInConstantRectangleWithoutWarp, // draw text with the biggest font possible while not exceeding rectangle dimensions, without word warp
                  AutoWarpInConstantRectangle, // draw text in rectangle while performing word warp. font size is a constant input. drawing may exceed bitmap rectangle.
                  AutoFitInConstantRectangleWithWarp // draw text with the biggest font possible while not exceeding rectangle dimensions, with word warp
              }
      
              private static void SetGraphicsHighQualityForTextRendering(Graphics g)
              {
                  // The smoothing mode specifies whether lines, curves, and the edges of filled areas use smoothing (also called antialiasing). One exception is that path gradient brushes do not obey the smoothing mode. Areas filled using a PathGradientBrush are rendered the same way (aliased) regardless of the SmoothingMode property.
                  g.SmoothingMode = SmoothingMode.AntiAlias;
      
                  // The interpolation mode determines how intermediate values between two endpoints are calculated.
                  g.InterpolationMode = InterpolationMode.HighQualityBicubic;
      
                  // Use this property to specify either higher quality, slower rendering, or lower quality, faster rendering of the contents of this Graphics object.
                  g.PixelOffsetMode = PixelOffsetMode.HighQuality;
      
                  // This one is important
                  g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
              }
      
              public static Size MeasureDrawTextBitmapSize(string text, Font font)
              {
                  Bitmap bmp = new Bitmap(1, 1);
                  using (Graphics g = Graphics.FromImage(bmp))
                  {
                      SizeF size = g.MeasureString(text, font);
                      return new Size((int)(Math.Ceiling(size.Width)), (int)(Math.Ceiling(size.Height)));
                  }
      
              }
      
              public static int GetMaximumFontSizeFitInRectangle(string text, Font font, RectangleF rectanglef, bool isWarp, int MinumumFontSize=6, int MaximumFontSize=1000)
              {
                  Font newFont;
                  Rectangle rect = Rectangle.Ceiling(rectanglef);
      
                  for (int newFontSize = MinumumFontSize; ; newFontSize++)
                  {
                      newFont = new Font(font.FontFamily, newFontSize, font.Style);
      
                      List<string> ls = WarpText(text, newFont, rect.Width);
      
                      StringBuilder sb = new StringBuilder();
                      if (isWarp)
                      {
                          for (int i = 0; i < ls.Count; ++i)
                          {
                              sb.Append(ls[i] + Environment.NewLine);
                          }
                      }
                      else
                      {
                          sb.Append(text);
                      }
      
                      Size size = MeasureDrawTextBitmapSize(sb.ToString(), newFont);
                      if (size.Width > rectanglef.Width || size.Height > rectanglef.Height)
                      {
                          return (newFontSize - 1);
                      }
                      if (newFontSize >= MaximumFontSize)
                      {
                          return (newFontSize - 1);
                      }
      
                  }
      
              }
      
              public static List<string> WarpText(string text, Font font, int lineWidthInPixels)
              {
                  string[] originalLines = text.Split(new string[] { " " }, StringSplitOptions.None);
      
                  List<string> wrappedLines = new List<string>();
      
                  StringBuilder actualLine = new StringBuilder();
                  double actualWidthInPixels = 0;
      
                  foreach (string str in originalLines)
                  {
                      Size size = MeasureDrawTextBitmapSize(str, font);
      
                      actualLine.Append(str + " ");
                      actualWidthInPixels += size.Width;
      
                      if (actualWidthInPixels > lineWidthInPixels)
                      {
                          actualLine =  actualLine.Remove(actualLine.ToString().Length - str.Length - 1, str.Length);
                          wrappedLines.Add(actualLine.ToString());
                          actualLine.Clear();
                          actualLine.Append(str + " ");
                          actualWidthInPixels = size.Width;
                      }
                  }
      
                  if (actualLine.Length > 0)
                  {
                      wrappedLines.Add(actualLine.ToString());
                  }
      
                  return wrappedLines;
              }
      
              public static Bitmap DrawTextToBitmap(string text, Font font, Color color, DrawMethod mode, RectangleF rectanglef)
              {
                  StringFormat drawFormat = new StringFormat();
                  Bitmap bmp;
                  switch (mode)
                  {
                      case DrawMethod.AutosizeAccordingToText:
                          {
                              Size size = MeasureDrawTextBitmapSize(text, font);
      
                              if (size.Width == 0 || size.Height == 0)
                              {
                                  bmp = new Bitmap(1, 1);
                              }
                              else
                              {
                                  bmp = new Bitmap(size.Width, size.Height);
                              }
      
                              using (Graphics g = Graphics.FromImage(bmp))
                              {
                                  SetGraphicsHighQualityForTextRendering(g);
      
                                  g.DrawString(text, font, new SolidBrush(color), 0, 0);
      
                                  return bmp;
                              }
      
                          }
                      case DrawMethod.AutoWarpInConstantRectangle:
                          {
                              Rectangle rect =  Rectangle.Ceiling(rectanglef);
                              bmp = new Bitmap(rect.Width,rect.Height);
      
                              if (rect.Width == 0 || rect.Height == 0)
                              {
                                  bmp = new Bitmap(1, 1);
                              }
                              else
                              {
                                  bmp = new Bitmap(rect.Width, rect.Height);
                              }
      
                              using (Graphics g = Graphics.FromImage(bmp))
                              {
                                  SetGraphicsHighQualityForTextRendering(g);
      
                                  g.DrawString(text, font, new SolidBrush(color), rectanglef, drawFormat);
      
                                  return bmp;
                              }
      
                          }
                      case DrawMethod.AutoFitInConstantRectangleWithoutWarp:
                          {
                              Rectangle rect = Rectangle.Ceiling(rectanglef);
      
                              bmp = new Bitmap(rect.Width, rect.Height);
      
                              if (rect.Width == 0 || rect.Height == 0)
                              {
                                  bmp = new Bitmap(1, 1);
                              }
                              else
                              {
                                  bmp = new Bitmap(rect.Width, rect.Height);
                              }
      
                              using (Graphics g = Graphics.FromImage(bmp))
                              {
                                  int fontSize = GetMaximumFontSizeFitInRectangle(text, font, rectanglef, false);
      
                                  SetGraphicsHighQualityForTextRendering(g);
      
                                  g.DrawString(text, new Font(font.FontFamily, fontSize,font.Style, GraphicsUnit.Point), new SolidBrush(color), rectanglef, drawFormat);
      
      
                                  return bmp;
                              }
      
                          }
                      case DrawMethod.AutoFitInConstantRectangleWithWarp:
                          {
                              Rectangle rect = Rectangle.Ceiling(rectanglef);
      
                              if (rect.Width == 0 || rect.Height == 0)
                              {
                                  bmp = new Bitmap(1, 1);
                              }
                              else
                              {
                                  bmp = new Bitmap(rect.Width, rect.Height);
                              }
      
                              using (Graphics g = Graphics.FromImage(bmp))
                              {
                                  int fontSize = GetMaximumFontSizeFitInRectangle(text, font, rectanglef, true);
      
                                  SetGraphicsHighQualityForTextRendering(g);
      
                                  g.DrawString(text, new Font(font.FontFamily, fontSize, font.Style, GraphicsUnit.Point), new SolidBrush(color), rectanglef, drawFormat);
      
      
                                  return bmp;
                              }
      
                          }
                  }
                  return null;
      
              }
      
      
      
          }
      }
      

      用法示例: Form1.cs

      using System;
      using System.Collections.Generic;
      using System.ComponentModel;
      using System.Data;
      using System.Drawing;
      using System.Globalization;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      using System.Windows.Forms;
      
      
      // add WindowsBase and PresentationCore assemblies
      
      namespace ReportPrepare
      {
          public partial class Form1 : Form
          {
              PictureBox picbox = new PictureBox();
              int i = 0;
              Timer t = new Timer();
      
              public Form1()
              {
                  InitializeComponent();
      
      
                  this.Controls.Add(picbox);
                  picbox.Dock = DockStyle.Fill;
      
                  t.Interval = 5000;
                  t.Tick += t_Tick;
                  t.Enabled = true;
      
                  this.Shown += Form1_Shown;
                  this.SizeChanged += Form1_SizeChanged;
      
                  this.Size = new Size(812, 400);
      
                  this.StartPosition = FormStartPosition.CenterScreen;
      
              }
      
              void Form1_Shown(object sender, EventArgs e)
              {
                  DrawText();
              }
      
              void t_Tick(object sender, EventArgs e)
              {
                  i++;
                  if (i > 3)
                  {
                      i = 0;
                  }
                  DrawText();
              }
      
      
              private void DrawText()
              {
      
                  // text and font
                  string text = "one two three four five six seven eight nine ten eleven twelve";
      
                  Font font = new System.Drawing.Font("Arial", 30, FontStyle.Regular, GraphicsUnit.Point);
      
                  switch (i)
                  {
                      case 0:
                          picbox.Image = TextDrawing.DrawTextToBitmap(text, font, Color.Red, TextDrawing.DrawMethod.AutosizeAccordingToText, new RectangleF(0, 0, picbox.Width, picbox.Height));
                          break;
                      case 1:
                          picbox.Image = TextDrawing.DrawTextToBitmap(text, font, Color.Red, TextDrawing.DrawMethod.AutoFitInConstantRectangleWithoutWarp, new RectangleF(0, 0, picbox.Width, picbox.Height));
                          break;
                      case 2:
                          picbox.Image = TextDrawing.DrawTextToBitmap(text, font, Color.Red, TextDrawing.DrawMethod.AutoWarpInConstantRectangle, new RectangleF(0, 0, picbox.Width, picbox.Height));
                          break;
                      case 3:
                          picbox.Image = TextDrawing.DrawTextToBitmap(text, font, Color.Red, TextDrawing.DrawMethod.AutoFitInConstantRectangleWithWarp, new RectangleF(0, 0, picbox.Width, picbox.Height));
                          break;
                  }
                  this.Text = ((TextDrawing.DrawMethod)(i)).ToString() + "                      Please resize window size by mouse to see drawing methods differences";
      
              }
      
              private void Form1_SizeChanged(object sender, EventArgs e)
              {
                  t.Enabled = false;
                  t.Enabled = true;
                  DrawText();
              }
      
      
      
      
      
          }
      }
      

      该示例每 5 秒自动在绘图模式之间切换一次。图片框停靠在主窗体内。调整表单大小向用户展示了绘图模式之间的差异。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-02-20
        • 1970-01-01
        • 2011-02-13
        • 2011-05-23
        • 2012-11-26
        • 2012-08-10
        • 2020-03-08
        • 2016-04-21
        相关资源
        最近更新 更多