使用Graphics.DrawString时动态调整字体大小以适应空间

有没有人有提示,而你可以动态调整字体大小以适应特定区域? 例如,我有一个800×110的矩形,我想用最大尺寸字体填充它,这将支持我试图显示的整个字符串。

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

显然,整个名称不会在大字体大小提供的空间中呈现。 必须有一个简单的方法来做到这一点?

您应该对Font.Size进行缩放转换,以下函数是这样做的一个示例,但您可以对其进行改进以应用更好的结果。

这是FindFont函数,它可以获得一个房间和一个首选大小的文本,并为您提供一种字体,您可以在其中设置整个文本适合房间!

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

对于您的问题,您可以像下面的代码一样调用它:

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

我已经适应了Saeed的强大function,以更符合我的要求。 评论解释所有:

  // You hand this the text that you need to fit inside some // available room, and the font you'd like to use. // If the text fits nothing changes // If the text does not fit then it is reduced in size to // make it fit. // PreferedFont is the Font that you wish to apply // FontUnit is there because the default font unit is not // always the one you use, and it is info required in the // constructor for the new Font. public static void FindGoodFont(Graphics Graf, string sStringToFit, Size TextRoomAvail, ref Font FontToUse, GraphicsUnit FontUnit) { // Find out what the current size of the string in this font is SizeF RealSize = Graf.MeasureString(sStringToFit, FontToUse); Debug.WriteLine("big string is {0}, orig size = {1},{2}", sStringToFit, RealSize.Width, RealSize.Height); if ((RealSize.Width <= TextRoomAvail.Width) && (RealSize.Height <= TextRoomAvail.Height)) { Debug.WriteLine("The space is big enough already"); // The current font is fine... return; } // Either width or height is too big... // Usually either the height ratio or the width ratio // will be less than 1. Work them out... float HeightScaleRatio = TextRoomAvail.Height / RealSize.Height; float WidthScaleRatio = TextRoomAvail.Width / RealSize.Width; // We'll scale the font by the one which is furthest out of range... float ScaleRatio = (HeightScaleRatio < WidthScaleRatio) ? ScaleRatio = HeightScaleRatio : ScaleRatio = WidthScaleRatio; float ScaleFontSize = FontToUse.Size * ScaleRatio; Debug.WriteLine("Resizing with scales {0},{1} chose {2}", HeightScaleRatio, WidthScaleRatio, ScaleRatio); Debug.WriteLine("Old font size was {0}, new={1} ",FontToUse.Size,ScaleFontSize); // Retain whatever the style was in the old font... FontStyle OldFontStyle = FontToUse.Style; // Get rid of the old non working font... FontToUse.Dispose(); // Tell the caller to use this newer smaller font. FontToUse = new Font(FontToUse.FontFamily, ScaleFontSize, OldFontStyle, FontUnit); } 

我不想反对saaeds解决方案,这可能也非常棒。 但我在msdn上发现了另一个: 动态图形文本resize对我有用 。

 public Font GetAdjustedFont(Graphics GraphicRef, string GraphicString, Font OriginalFont, int ContainerWidth, int MaxFontSize, int MinFontSize, bool SmallestOnFail) { // We utilize MeasureString which we get via a control instance for (int AdjustedSize = MaxFontSize; AdjustedSize >= MinFontSize; AdjustedSize--) { Font TestFont = new Font(OriginalFont.Name, AdjustedSize, OriginalFont.Style); // Test the string with the new size SizeF AdjustedSizeNew = GraphicRef.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 new Font(OriginalFont.Name,MinFontSize,OriginalFont.Style); } else { return OriginalFont; } } 

这只是@ Saeed的FindFontfunction的更新。

需要将GraphicsUnit.Pixel添加到FindFont函数返回行。 如果没有GraphicsUnit.Pixel ,系统dpi将影响绘制的字符串。 当系统和位图的dpi不匹配时会出现问题。 您可以在此Windows DPI设置中看到更多细节会影响Graphics.DrawString 。 由于PreferedFont GraphicsUnit已设置为GraphicsUnit.Pixel ,因此未使用GraphicsUnit.Pixel设置返回字体。 在这种情况下,如果位图dpi大于系统dpi,则文本将超出Room维度,如果位图dpi小于系统dpi,则字体大小将小于预期大小。 这是更新的function。

  private Font FindFont( System.Drawing.Graphics g , string longString , Size Room , Font PreferedFont) { 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,PreferedFont.Style,GraphicsUnit.Pixel); } 

这是我支持包装的解决方案。

 public static Font GetAdjustedFont(Graphics graphic, string str, Font originalFont, Size containerSize) { // We utilize MeasureString which we get via a control instance for (int adjustedSize = (int)originalFont.Size; adjustedSize >= 1; adjustedSize--) { var testFont = new Font(originalFont.Name, adjustedSize, originalFont.Style, GraphicsUnit.Pixel); // Test the string with the new size var adjustedSizeNew = graphic.MeasureString(str, testFont, containerSize.Width); if (containerSize.Height > Convert.ToInt32(adjustedSizeNew.Height)) { // Good font, return it return testFont; } } return new Font(originalFont.Name, 1, originalFont.Style, GraphicsUnit.Pixel); } 

如何使用:

 var font = GetAdjustedFont(drawing, text, originalfont, wrapSize); drawing.DrawString(text, font, textBrush, new Rectangle(0, 0, wrapSize.Width, wrapSize.Height));