【问题标题】:How to create a font with precise character height in Windows Forms?如何在 Windows 窗体中创建具有精确字符高度的字体?
【发布时间】:2012-08-18 04:56:18
【问题描述】:

在我的程序中,我需要生成一个位图,其中包含从左到右排列的所有数字字符 (0..9),以及一些其他字符。

用户将从 UI 中选择:

  1. 所需的字体,以及
  2. 所需的字符高度(以像素为单位)。

所以我想创建一个位图,然后从这个位图中创建一个图形,然后将数字一个一个地绘制到这个位图中,然后将它保存到磁盘。

几个小时后我无法弄清楚的事情: 如何创建正确大小的字体,以使数字“0”具有用户指定的高度?

我使用了 Font 构造函数中的所有参数,使用 StringFormat 的属性,使用 MeasureString/MeasureText/MeasureCharacterRanges,我尝试通过 P/Invoke(使用正/负 nHeight)使用本机 CreateFont() 创建字体。所有称为“大小”或“高度”的参数似乎都表示某个比“0”大得多的假设字符的大小。

我确实阅读了有关线高、em 高度、上升、下降等的理论。似乎没有关于字符的 真实高度的概念,没有填充和间距等 p>

又是我的问题:给定“0”字形的字体名称和所需的像素高度,我如何创建一种字体来绘制具有所需高度的字形?

如有任何指导,我将不胜感激。

稍后编辑 关于我的项目的更多细节:它是一个带有大显示屏的嵌入式设备,我需要为设计人员提供一种简单的方法来生成和尝试他们喜欢的位图字体。生成此类位图字体的 Windows 工具对我来说似乎是一个很好的解决方案。

【问题讨论】:

  • 基于 GDI+ 的文本测量有点奇怪。查看普通的 GDI API。关于垂直居中文本的其他一些问题可能会有所帮助。
  • 系统字体系统将始终为异常高或低的字符保留空间。为什么不尝试“测试和解决”循环呢?打印字符零,并以编程方式测量其高度(以像素为单位) - 例如检查以确保水平方向至少十行像素至少设置了一位。然后如果失败则将字体大小增加一并重试直到成功。不幸的是,您必须剪掉未使用的像素行,因为会有一些重叠。
  • 是的,我想到了这样的事情,但我想把它作为最后的解决方案。我正在查看愚蠢的 Paint 程序,它以某种方式设法完全满足我的需要(我告诉它“Arial 10”,它绘制的文本正好是 10 像素高),我希望有一种明确的编程方式来做到这一点......

标签: c# winforms fonts font-size


【解决方案1】:

我相信您可以使用此Font ConstructorGraphicsUnit 指定为像素。然后它应该创建具有适当大小的字体。

添加测试代码 - 根据您的情况进行相应编辑,不要判断样式,我只是想要一些可以粘贴到 LINQPad 中并生成图像的内容。

using (var font = new Font("Arial",10,FontStyle.Regular, GraphicsUnit.Pixel))
using (var image = new Bitmap(30, 15))
using (var graphics = Graphics.FromImage(image))
{
    graphics.FillRectangle(Brushes.White, new Rectangle(0, 0, 30, 15));
    graphics.DrawString("Ay", font, Brushes.Black, 0, 0);
    image.Save(@"E:\test.bmp", ImageFormat.Bmp);
}

请记住,在按像素设置大小时,字体中的所有字符都需要适合该范围,这意味着字母带有降序,字母带有升序。

【讨论】:

  • 这是我尝试的第一件事。我刚刚再次对其进行了测试:从 Arial 10 我得到一个 7 像素高的“0”。
  • 这确实按预期工作。您刚刚尝试了 A,然后执行 Ay,您将看到该行的总高度为 10。
  • 感谢您的示例,但这不是我需要的。我需要的是最初的问题。我将在这里用另一种方式写它:如何计算传递给 Font() 构造函数的大小,以便给定字体的字形“0”(不是字符串“Ay”)具有给定的高度?关于我的项目的更多细节:它是一个带有大显示屏的嵌入式设备,我需要为设计人员提供一种简单的方法来生成和尝试他们喜欢的位图字体。生成此类位图的 Windows 工具对我来说似乎是一个很好的解决方案。
【解决方案2】:

虽然我之前发布的内容与我之前发布的内容相差无几,但它实际上并没有奏效。在对此进行猛烈抨击时,我发现有趣的是,graphics.MeasureString("M", ...) 报告的高度远大于 graphics.MeasureString("MM", ...)。在手动计算字体大小时,我发现第一个(与 GetEMSize 的响应相关)实际上是全线大小。最后,我意识到数字的实际字符大小不需要与任何指标相关联,无论是真实的还是 .net。

【讨论】:

    猜你喜欢
    • 2012-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-22
    • 2010-11-24
    • 2013-05-24
    • 2012-01-07
    • 2017-06-28
    相关资源
    最近更新 更多