为什么我必须将MeasureString()
结果宽度增加21%
size.Width = size.Width * 1.21f;
逃避DrawString()
中的Word Wrap?
我需要一个解决方案来获得确切的结果。
相同的字体,相同的stringformat,两个函数中使用的文本相同。
来自OP的回答:
SizeF size = graphics.MeasureString(element.Currency, Currencyfont, new PointF(0, 0), strFormatLeft);
size.Width = size.Width * 1.21f;
int freespace = rect.Width - (int)size.Width;
if (freespace < ImageSize) { if (freespace > 0) ImageSize = freespace; else ImageSize = 0; }
int FlagY = y + (CurrencySize - ImageSize) / 2;
int FlagX = (freespace - ImageSize) / 2;
graphics.DrawImage(GetResourseImage(@"Flags." + element.Flag.ToUpper() + ".png"),
new Rectangle(FlagX, FlagY, ImageSize, ImageSize));
graphics.DrawString(element.Currency, Currencyfont, Brushes.Black,
new Rectangle(FlagX + ImageSize, rect.Y, (int)(size.Width), CurrencySize), strFormatLeft);
我的代码。
答案 0 :(得分:6)
MeasureString()方法存在一些问题,尤其是在绘制非ASCII字符时。请改为尝试TextRenderer.MeasureText()。
答案 1 :(得分:3)
Graphics.MeasureString,TextRenderer.MeasureText和Graphics.MeasureCharacterRanges 所有返回的大小都包含字形周围的空白像素,以容纳上升和下降。
换句话说,它们返回“a”的高度与“d”(上升)或“y”(下降)的高度相同。如果您需要字形的真实大小,唯一的方法是绘制字符串并计算像素:
Public Shared Function MeasureStringSize(ByVal graphics As Graphics, ByVal text As String, ByVal font As Font) As SizeF
' Get initial estimate with MeasureText
Dim flags As TextFormatFlags = TextFormatFlags.Left + TextFormatFlags.NoClipping
Dim proposedSize As Size = New Size(Integer.MaxValue, Integer.MaxValue)
Dim size As Size = TextRenderer.MeasureText(graphics, text, font, proposedSize, flags)
' Create a bitmap
Dim image As New Bitmap(size.Width, size.Height)
image.SetResolution(graphics.DpiX, graphics.DpiY)
Dim strFormat As New StringFormat
strFormat.Alignment = StringAlignment.Near
strFormat.LineAlignment = StringAlignment.Near
' Draw the actual text
Dim g As Graphics = graphics.FromImage(image)
g.SmoothingMode = SmoothingMode.HighQuality
g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAliasGridFit
g.Clear(Color.White)
g.DrawString(text, font, Brushes.Black, New PointF(0, 0), strFormat)
' Find the true boundaries of the glyph
Dim xs As Integer = 0
Dim xf As Integer = size.Width - 1
Dim ys As Integer = 0
Dim yf As Integer = size.Height - 1
' Find left margin
Do While xs < xf
For y As Integer = ys To yf
If image.GetPixel(xs, y).ToArgb <> Color.White.ToArgb Then
Exit Do
End If
Next
xs += 1
Loop
' Find right margin
Do While xf > xs
For y As Integer = ys To yf
If image.GetPixel(xf, y).ToArgb <> Color.White.ToArgb Then
Exit Do
End If
Next
xf -= 1
Loop
' Find top margin
Do While ys < yf
For x As Integer = xs To xf
If image.GetPixel(x, ys).ToArgb <> Color.White.ToArgb Then
Exit Do
End If
Next
ys += 1
Loop
' Find bottom margin
Do While yf > ys
For x As Integer = xs To xf
If image.GetPixel(x, yf).ToArgb <> Color.White.ToArgb Then
Exit Do
End If
Next
yf -= 1
Loop
Return New SizeF(xf - xs + 1, yf - ys + 1)
End Function
答案 2 :(得分:2)
如果它对任何人有帮助,我将回答从smirkingman转换为C#,修复了内存错误(使用 - Dispose)和外部循环中断(没有TODO)。我也在图形(和字体)上使用缩放,所以我也添加了(否则不起作用)。它返回RectangleF,因为我想精确定位文本(使用Graphics.DrawText)。
不完美,但足以满足我的目的源代码:
static class StringMeasurer
{
private static SizeF GetScaleTransform(Matrix m)
{
/*
3x3 matrix, affine transformation (skew - used by rotation)
[ X scale, Y skew, 0 ]
[ X skew, Y scale, 0 ]
[ X translate, Y translate, 1 ]
indices (0, ...): X scale, Y skew, Y skew, X scale, X translate, Y translate
*/
return new SizeF(m.Elements[0], m.Elements[3]);
}
public static RectangleF MeasureString(Graphics graphics, Font f, string s)
{
//copy only scale, not rotate or transform
var scale = GetScaleTransform(graphics.Transform);
// Get initial estimate with MeasureText
//TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.NoClipping;
//Size proposedSize = new Size(int.MaxValue, int.MaxValue);
//Size size = TextRenderer.MeasureText(graphics, s, f, proposedSize, flags);
SizeF sizef = graphics.MeasureString(s, f);
sizef.Width *= scale.Width;
sizef.Height *= scale.Height;
Size size = sizef.ToSize();
int xLeft = 0;
int xRight = size.Width - 1;
int yTop = 0;
int yBottom = size.Height - 1;
// Create a bitmap
using (Bitmap image = new Bitmap(size.Width, size.Height))
{
image.SetResolution(graphics.DpiX, graphics.DpiY);
StringFormat strFormat = new StringFormat();
strFormat.Alignment = StringAlignment.Near;
strFormat.LineAlignment = StringAlignment.Near;
// Draw the actual text
using (Graphics g = Graphics.FromImage(image))
{
g.SmoothingMode = graphics.SmoothingMode;
g.TextRenderingHint = graphics.TextRenderingHint;
g.Clear(Color.White);
g.ScaleTransform(scale.Width, scale.Height);
g.DrawString(s, f, Brushes.Black, new PointF(0, 0), strFormat);
}
// Find the true boundaries of the glyph
// Find left margin
for (; xLeft < xRight; xLeft++)
for (int y = yTop; y <= yBottom; y++)
if (image.GetPixel(xLeft, y).ToArgb() != Color.White.ToArgb())
goto OUTER_BREAK_LEFT;
OUTER_BREAK_LEFT: ;
// Find right margin
for (; xRight > xLeft; xRight--)
for (int y = yTop; y <= yBottom; y++)
if (image.GetPixel(xRight, y).ToArgb() != Color.White.ToArgb())
goto OUTER_BREAK_RIGHT;
OUTER_BREAK_RIGHT: ;
// Find top margin
for (; yTop < yBottom; yTop++)
for (int x = xLeft; x <= xRight; x++)
if (image.GetPixel(x, yTop).ToArgb() != Color.White.ToArgb())
goto OUTER_BREAK_TOP;
OUTER_BREAK_TOP: ;
// Find bottom margin
for (; yBottom > yTop; yBottom-- )
for (int x = xLeft; x <= xRight; x++)
if (image.GetPixel(x, yBottom).ToArgb() != Color.White.ToArgb())
goto OUTER_BREAK_BOTTOM;
OUTER_BREAK_BOTTOM: ;
}
var pt = new PointF(xLeft, yTop);
var sz = new SizeF(xRight - xLeft + 1, yBottom - yTop + 1);
return new RectangleF(pt.X / scale.Width, pt.Y / scale.Height,
sz.Width / scale.Width, sz.Height / scale.Height);
}
}
答案 3 :(得分:1)
就个人而言,最有效的方法以及我所推荐的方法一直是:
const TextFormatFlags _textFormatFlags = TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix | TextFormatFlags.PreserveGraphicsClipping;
// Retrieve width
int width = TextRenderer.MeasureText(element.Currency, Currencyfont, new Size(short.MaxValue, short.MaxValue), _textFormatFlags).Width + 1;
// Retrieve height
int _tempHeight1 = TextRenderer.MeasureText("_", Currencyfont).Height;
int _tempHeight2 = (int)Math.Ceiling(Currencyfont.GetHeight());
int height = Math.Max(_tempHeight1, _tempHeight2) + 1;
答案 4 :(得分:0)
This文章提供了两种方法来获取DrawString呈现的字符的确切大小。
答案 5 :(得分:-1)
您可能需要在StringFormat
标志中添加以下内容:
StringFormatFlags.FitBlackBox
答案 6 :(得分:-1)
尝试此解决方案:http://www.codeproject.com/Articles/2118/Bypass-Graphics-MeasureString-limitation (发现于https://stackoverflow.com/a/11708952/908936)
代码:
static public int MeasureDisplayStringWidth(Graphics graphics, string text, Font font)
{
System.Drawing.StringFormat format = new System.Drawing.StringFormat ();
System.Drawing.RectangleF rect = new System.Drawing.RectangleF(0, 0, 1000, 1000);
var ranges = new System.Drawing.CharacterRange(0, text.Length);
System.Drawing.Region[] regions = new System.Drawing.Region[1];
format.SetMeasurableCharacterRanges (new[] {ranges});
regions = graphics.MeasureCharacterRanges (text, font, rect, format);
rect = regions[0].GetBounds (graphics);
return (int)(rect.Right + 1.0f);
}