【问题标题】:Strange behavior of graphics.MeasureString at different resolutionsgraphics.MeasureString 在不同分辨率下的奇怪行为
【发布时间】:2012-03-02 08:48:56
【问题描述】:

我注意到 Graphics.MeasureString 在不同分辨率下的奇怪行为。

对于默认分辨率 (96x96),我测试的不同字体大小之间存在线性关系。

但是,如果我将它提高到 512 x 512,线性关系就会消失,并且在使用度量字符串时会发生一些非常奇怪的事情。 (参见下面的 4 个图)

如果我将图形对象的分辨率保持在默认大小,并测量字体大小,这里是字体大小和字符串宽度之间的关系:

图形对象,默认分辨率 (96):

字体大小(X 轴),特定字符串的宽度(Y 轴)

字体大小(X 轴),特定字符串的高度(Y 轴)

但是,如果我改变分辨率

图形对象,512分辨率:

字体大小(X 轴),特定字符串的宽度(Y 轴)

字体大小(X 轴),特定字符串的高度(Y 轴)

有人知道为什么会这样吗?

谢谢。

应该注意我使用的是 .NET 4(完整配置文件)

用于生成图表的代码(更改每种类型的分辨率):

string str = "6  CN-3 Tie EomgVeo405- 2ss>era09rni IBne 20iopv Atdrsn - Ng72";
SizeF sizef = new SizeF(855, 14.000001f);
StringFormat stringFormat = new StringFormat() 
{
    Alignment = StringAlignment.Center,
    LineAlignment = StringAlignment.Near,
    Trimming = StringTrimming.None,
    FormatFlags = StringFormatFlags.NoClip,
};

Bitmap b = new Bitmap(901, 401);
//b.SetResolution(512, 512);
Graphics g = Graphics.FromImage(b);

for (float x = origFont.Size; x >= 0.5; x -= 0.1f)
{
    var data = g.MeasureString(str, new Font("Microsoft Sans Serif", x), sizef, stringFormat);
    Console.WriteLine(x + "\t" + data.Width + "\t" + data.Height);
}

【问题讨论】:

  • Graphics.MeasureString() 非常糟糕,在 .NET 版本 2 中被 TextRenderer.MeasureText() 取代。否则,您可以从 TrueType 提示算法中获得这种模式。以小于 8 的点或像素大小渲染文本否则毫无意义。
  • 当宽度达到 850 时它开始“卡顿”。这是我输入 Graphics.MeasureString 的最大允许宽度。正如 Lasse V. Karlsen 指出的那样,该死的东西正在包装。我未能添加“不换行”标志。谢谢大家!

标签: c# .net graphics gdi+ resolution


【解决方案1】:

这个答案是一个猜测,但证据完全符合它。

你看到的是字符串被包裹成两行。

假设如下:

  1. 文本的宽度与字体大小成线性比例
  2. 文本的高度与字体大小成线性比例

这适合您的 512 分辨率图的开始,一切都线性增加。

在某些时候,宽度会急剧减少一定量,同时高度会增加一倍。

这意味着一个单词被移到了第 2 行,它的高度增加了一倍(2 行与之前的 1 行),并且由于行上的最后一个单词现在位于行首,因此字符串的宽度减小了一定数量2.

从那里开始,随着字体大小的增加,仍然在第 1 行的字符串部分线性变宽,宽度再次缓慢增加。同时高度线性增加,但现在的速度是中断前的两倍,因为现在有 2 条线变得更高,而之前是 1 条。

在某个时刻,第 1 行的最后一个单词再次打破了最大宽度,并在第 2 行向下移动,在之前单独存在的单词之前,并且在该点,宽度再次急剧减小了一定金额。

如果您要继续您的图表,我预测宽度将继续其当前模式。它每次下降的确切量与被移动的单词的宽度成正比。同时,在某些时候第二条线需要被打破,在这种情况下,你会得到 3 倍的高度,然后高度会以 3 倍的速度增加,依此类推。

【讨论】:

  • 虽然我还没有证实这一点 - 看看我的情节,这似乎是合乎逻辑的,因为当字符串宽度达到 850 时会发生“口吃” - 这正是我提供 Graphics.MeasureString 的允许宽度的宽度.谢谢!我应该明白这一点,我责怪阅读到凌晨 3 点:D
  • 那么,请确认一下 :) 这里的其他答案告诉我,我对文本渲染和 .NET 的了解并不像我想的那样多,所以我可能在这里遗漏了一些东西.不过,它似乎确实适合:)
  • 这是由于缺少 NoWrap 标志。口吃总是发生在 850 的事实是确凿无疑的。我确实确认了。谢谢!
【解决方案2】:

我相信这可能是由于 GDI+ 中的提示/网格拟合算法而发生的。就字形易读性而言,测试中的字体尺寸非常小,因此,渲染引擎会尝试对每个字形应用特殊转换以使其更清晰。这些转换很大程度上取决于目标 DPI。

还值得一提的是,字体大小的大幅增加将导致更“线性”的依赖性。

articlearticle 通过一些示例更详细地解释了这些机制。

同时,您可以尝试修改Graphics.TextRenderingHint 属性和/或尝试使用TextRenderer 而不是Graphics.DrawString,如果这样可以帮助您解决问题。

【讨论】:

  • 感谢您的提示。今后我也会关注此事。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-06
  • 2014-05-17
相关资源
最近更新 更多