.net - TextRenderer.MeasureText 似乎要四舍五入字体大小
问题描述
据我所知,当你使用TextRenderer.MeasureText
查找字符的宽度时,在我的情况下是固定宽度CourierNew
字符,当字体大小具有小数部分时,我会得到奇怪的结果,例如 11.3 而不是 11.0 或 12.0。
例如
Dim font As Font = New Font("Courier New", emSize:=11.3)
Dim width As Double = TextRenderer.MeasureText(New String("0"c, 1000), font).Width / 1000
(我正在平均一个长字符串的长度以考虑填充。)
结果
emSize = 11.0 -> width = 9.008
emSize = 12.0 -> width = 10.008
emSize = 11.3 -> width = 10.008
emSize = 11.7 -> width = 10.008
我做错了什么还是这是预期的行为?
解决方案
唯一与返回的值TextRenderer.MeasureText()
相关的是,当文本由TextRenderer.DrawText()
. 所以,真正的问题是:当方法被调用时,返回的大小是否MeasureText()
与发生的匹配。DrawText()
事实上,他们确实:
以上是一个简单程序(下面的代码)的输出,该程序以您所询问的四种不同字体大小、四种不同方式呈现十位数字的示例字符串。前两组使用 渲染TextRenderer.DrawText()
,后两组使用 渲染Graphics.DrawString()
。
请注意,使用 时TextRenderer
,四种尺寸中的三种呈现完全相同。因此,当然,当您测量文本时,测量的宽度也将完全相同。
对于使用的两种渲染方法中的每一种,实际上都会进行两次渲染,一次使用Graphics
对象的默认设置,然后再次使用Graphics.TextRenderingHint
set to AntiAlias
。有趣的是,至少在我的电脑上,虽然AntiAlias
设置了让TextRenderer
输出看起来更好,但使用该Graphics.DrawString()
方法时它看起来更糟(事实上,它看起来很像TextRenderer
设置为默认值时的输出SystemDefault
)。
更重要的是,请注意,虽然TextRenderer
不随小数字体大小缩放,Graphics.DrawString()
但可以。这两种渲染方式有着根本的不同。如果你想要小数字体大小,你需要使用支持它的渲染方法。TextRenderer
不是吗。
代码示例:
在 Visual Studio 中一个全新的 Windows 窗体项目中,您可以将这些成员添加到Form1
类中,以生成上面的输出:
private readonly IReadOnlyList<float> _emSizes = new[] { 11.0f, 11.3f, 11.7f, 12.0f };
private const string _text = "0123456789";
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
int y = _DrawTextExamples(e.Graphics, _text, 0, _emSizes) + 10;
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
y = _DrawTextExamples(e.Graphics, _text, y, _emSizes) + 10;
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SystemDefault;
y = _DrawTextExamplesWithDrawString(e.Graphics, _text, y, _emSizes) + 10;
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
y = _DrawTextExamplesWithDrawString(e.Graphics, _text, y, _emSizes) + 10;
}
private int _DrawTextExamples(Graphics g, string text, int y, IReadOnlyList<float> emSizes)
{
Point pt = new Point(0, y);
foreach (float emSize in emSizes)
{
using (Font font = new Font("Courier New", emSize))
{
Size size = TextRenderer.MeasureText(g, text, font);
TextRenderer.DrawText(g, text, font, pt, Color.Black);
pt.X += size.Width + 20;
TextRenderer.DrawText(g, $"emSize: {emSize}, width: {size.Width}", font, pt, Color.Black);
pt = new Point(0, pt.Y + size.Height);
}
}
return pt.Y;
}
private int _DrawTextExamplesWithDrawString(Graphics g, string text, int y, IReadOnlyList<float> emSizes)
{
PointF pt = new Point(0, y);
foreach (float emSize in emSizes)
{
using (Font font = new Font("Courier New", emSize))
{
SizeF size = g.MeasureString(text, font);
g.DrawString(text, font, Brushes.Black, pt);
pt.X += size.Width + 20;
g.DrawString($"emSize: {emSize}, width: {size.Width}", font, Brushes.Black, pt);
pt = new PointF(0, pt.Y + size.Height);
}
}
return (int)pt.Y + 1;
}
推荐阅读
- apache-nifi - Nifi 在从 oracle 数据库读取时附加了额外的字符
- java - 从 POST 请求中检索数据时出错
- mongodb - “没有反应堆在运行,必须从 Tokio 1.x 运行时的上下文中调用”当将 mongodb 2 与 actix-web 3 一起使用时
- excel - Excel VBA - Financial Model Color Formatting
- kubernetes - 如何识别 statefulset 中不健康的 pod
- matrix - 在 Julia 中将元组向量转换为矩阵
- google-cloud-platform - 谷歌云计费帐户的问题
- javascript - 与 www 崩溃的 http 请求
- python - 如果 Internet 出现故障,Colab 笔记本执行将失败。如何防止这种情况?
- javascript - 如何使用上下文桥将类传递给渲染器进程