C# 使用 Graphics.DrawString 时动态调整字体大小以适应空间
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19674743/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dynamically resizing font to fit space while using Graphics.DrawString
提问by farina
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.
有没有人有提示,而您可以动态调整字体大小以适应特定区域?例如,我有一个 800x110 的矩形,我想用最大尺寸的字体填充它,以支持我尝试显示的整个字符串。
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?
显然,整个名称不会在以大字体提供的空间中呈现。必须有一个简单的方法来做到这一点?
采纳答案by saeed
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.
您应该对Font.Size
以下函数进行比例变换是这样做的一个示例,但您可以改进它以应用更好的结果。
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!
这是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);
}
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
);
}
回答by Owen Ransen
I've adapted Saeed's great function to more suit my requirements. Comments explain all:
我已经调整了 Saeed 的强大功能以更适合我的要求。评论解释了一切:
// 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);
}
回答by Jürgen Steinblock
I don't want to bash against saaeds solution which is probably pretty awesome, too. But I found another one on msdn: Dynamic Graphic Text Resizingwhich worked for me.
我不想抨击 saaeds 解决方案,这也可能非常棒。但是我在 msdn 上找到了另一个:Dynamic Graphic Text Resizing,它对我有用。
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;
}
}
回答by Rijul Sudhir
This is just an update for @Saeed's FindFont
function.
这只是@SaeedFindFont
功能的更新。
GraphicsUnit.Pixel
needs to be added to FindFont
function return line. Without GraphicsUnit.Pixel
, system dpi will effect the drawn string. Problem will arise when the dpi of system and bitmap mismatches. You can see more detail in this Windows DPI setting affects Graphics.DrawString. Since GraphicsUnit of PreferedFont
is already set to GraphicsUnit.Pixel
and return font is not set with GraphicsUnit.Pixel
. In this case text will go out of the Room
dimension, if bitmap dpi is larger than system dpi and font size will go smaller than the expected size if bitmap dpi is smaller than system dpi. Here is the updated function.
GraphicsUnit.Pixel
需要添加到FindFont
函数返回行。如果没有GraphicsUnit.Pixel
,系统 dpi 将影响绘制的字符串。当系统的dpi和位图不匹配时就会出现问题。您可以在此Windows DPI 设置影响 Graphics.DrawString 中看到更多详细信息。由于 GraphicsUnit ofPreferedFont
已设置为GraphicsUnit.Pixel
并且返回字体未设置为GraphicsUnit.Pixel
。在这种情况下Room
,如果位图 dpi 大于系统 dpi,则文本将超出维度,如果位图 dpi 小于系统 dpi,则字体大小将小于预期大小。这是更新的功能。
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);
}
回答by Saykor
Here is my solution that support wrapping.
这是我支持包装的解决方案。
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);
}
How to use:
如何使用:
var font = GetAdjustedFont(drawing, text, originalfont, wrapSize);
drawing.DrawString(text, font, textBrush, new Rectangle(0, 0, wrapSize.Width, wrapSize.Height));