如何测量给定字体/大小的数字的像素宽度 (C#)

发布于 2024-08-13 01:24:48 字数 835 浏览 4 评论 0原文

我正在尝试计算 Excel 列的像素宽度,如 这篇文章,使用 OpenXML 规范中的官方公式。但是,为了应用这个公式,我需要知道 Normal 字体的 最大数字宽度,即最宽数字的像素宽度。 OpenXML 规范给出了这个例子作为说明:

以 Calibri 字体为例,11 点字体的最大数字宽度 大小为 7 像素(96 dpi)。

我通过目视检查 Calibri 11 点数字来检查这是否正确,它确实是 7 像素宽。因此,我正在尝试创建一种方法,该方法将返回任何字体/大小的最大数字宽度。

我已遵循此问题中提出的建议,但它不会产生我期望的结果。

这是我的测试代码:

var font = new Font("Calibri", 11.0f, FontStyle.Regular);

for (var i = 0; i < 10; i++)
{
    Debug.WriteLine(TextRenderer.MeasureText(i.ToString(), font));
}

这报告所有数字的宽度为 15。

请问有什么建议吗?

谢谢, 蒂姆

I am trying to calculate the pixel width of Excel columns, as described in this post, using the official formula from the OpenXML specification. However, in order to apply this formula, I need to know the Maximum Digit Width of the Normal font, which is the pixel width of the widest numeric digit. The OpenXML specification gives this example as a clarification:

Using the Calibri font as an example, the maximum digit width of 11 point font
size is 7 pixels (at 96 dpi).

I have checked that this is correct by visually examining a Calibri 11-point digit and it is indeed 7 pixels wide. So, I am trying to create a method that will return the maximum digit width for any font / size.

I have followed the recommendations made in this question, but it doesn't produce the results I am expecting.

Here's my test code:

var font = new Font("Calibri", 11.0f, FontStyle.Regular);

for (var i = 0; i < 10; i++)
{
    Debug.WriteLine(TextRenderer.MeasureText(i.ToString(), font));
}

This reports that all digits have a width of 15.

Any suggestions please?

Thanks,
Tim

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

疑心病 2024-08-20 01:24:48

首先我要说的是,我将要展示的代码看起来像是一个可怕的黑客攻击,我不会将其作为解决方案来呈现。相反,我希望它能更多地揭示 MeasureText 的行为,这可能会引导您找到最终的解决方案。

我对你的代码做了一些轻微的修改。我正在测量两个下划线字符的长度。然后,在 for 循环体中,我测量两侧带有下划线的所需字符,并单独减去两个下划线字符的长度。对于测试场景,我得到的结果为 7。这样做的主要目的是确定 MeasureText 是逐个字符地填充还是在字符串的开头/结尾处填充。看来是后者了。也许这与您收到的其他一些输入相结合,将引导您找到更优雅的解决方案。

var font = new Font("Calibri", 11.0f, FontStyle.Regular);
int underscoreWidth = TextRenderer.MeasureText("__", font).Width; 
for (var i = 0; i < 10; i++)
   {
      int charWidth = TextRenderer.MeasureText(String.Concat("_", i.ToString(), "_"), font).Width - underscoreWidth;
      Debug.WriteLine(charWidth);
   }

First let me say that the code I'm about to show looks like a horrible hack and I'm not presenting it as a solution. Rather, I'm hoping it reveals a little more about the behavior of MeasureText that might lead you to your final solution.

I made a slight alteration to your code. I'm measuring the length of two underscore characters. Then, in the body of the for loop I'm measuring the desired character with underscores on either side and subtracting the length of the two underscore characters alone. For the test scenario I am getting a result of 7. The main purpose of this was to determine whether MeasureText is accounting for padding on a character-by-character basis or padding at the beginning/ending of the string. It seems that it is the latter. Perhaps this, combined with some of the other input you've received, will lead you to a more elegant solution.

var font = new Font("Calibri", 11.0f, FontStyle.Regular);
int underscoreWidth = TextRenderer.MeasureText("__", font).Width; 
for (var i = 0; i < 10; i++)
   {
      int charWidth = TextRenderer.MeasureText(String.Concat("_", i.ToString(), "_"), font).Width - underscoreWidth;
      Debug.WriteLine(charWidth);
   }
情何以堪。 2024-08-20 01:24:48

TextRenderer 并不总是如您所期望的那样准确:

来自 MSDN: http:// msdn.microsoft.com/en-us/library/8wafk2kt.aspx

例如,TextRenderer 的默认行为是向绘制文本的边界矩形添加填充,以容纳悬垂字形

您有 Graphics 对象还是 Control 对象吗?如果您使用这些,您可以按照您期望的方式获得准确的结果。

查看 http://msdn.microsoft.com /en-us/library/6xe5hazb(VS.80).aspx

TextRenderer is not always accurate the way you would expect:

From MSDN: http://msdn.microsoft.com/en-us/library/8wafk2kt.aspx

For example, the default behavior of the TextRenderer is to add padding to the bounding rectangle of the drawn text to accommodate overhanging glyphs

Do you have a Graphics object or a Control object? If you are using these you can get accurate restults the way you would expect.

Take a look at http://msdn.microsoft.com/en-us/library/6xe5hazb(VS.80).aspx

·深蓝 2024-08-20 01:24:48

MeasureText 添加填充,尽管它大致随字体大小线性缩放,但其数量相当不可预测。诀窍是减去两个测量值以消除填充。这段代码生成了非常令人满意的数字:

        float size = 5;
        for (int ix = 0; ix < 10; ++ix) {
            var font = new Font("Calibri", size, FontStyle.Regular);
            string txt = new string('0', 100);
            SizeF sz1 = TextRenderer.MeasureText("00", font) - TextRenderer.MeasureText("0", font);
            Console.WriteLine("{0} {1:N3}", size, sz1.Width);
            size += 2;
        }

输出:

5 4.000
7 5.000
9 6.000
11 7.000
13 9.000
15 10.000
17 12.000
19 13.000
21 14.000
23 16.000

这为您提供了您正在寻找的 7 个像素。请注意,您必须适应 TrueType 提示,它可以调整数字的形状,使其主干落在像素边界上。添加至少一个像素。

MeasureText adds padding, the amount is fairly unpredictable although it roughly scales linearly with the font size. The trick is to subtract two measurements to get rid of the padding. This code generated very happy numbers:

        float size = 5;
        for (int ix = 0; ix < 10; ++ix) {
            var font = new Font("Calibri", size, FontStyle.Regular);
            string txt = new string('0', 100);
            SizeF sz1 = TextRenderer.MeasureText("00", font) - TextRenderer.MeasureText("0", font);
            Console.WriteLine("{0} {1:N3}", size, sz1.Width);
            size += 2;
        }

Output:

5 4.000
7 5.000
9 6.000
11 7.000
13 9.000
15 10.000
17 12.000
19 13.000
21 14.000
23 16.000

That gets you the 7 pixels you're looking for. Beware that you'll have to accommodate TrueType hinting, it can adjust the shape of the digit so that its main stems fall on pixel boundaries. Add at least one pixel.

薄荷港 2024-08-20 01:24:48

测量文本宽度可能是一场噩梦。我不知道为什么他们让它如此令人困惑。

这是我测量文本长度的最准确方法:

    protected int _MeasureDisplayStringWidth ( Graphics graphics, string text, Font font )
    {
        if ( text == "" )
            return 0;

        StringFormat format = new StringFormat ( StringFormat.GenericDefault );
        RectangleF rect = new RectangleF ( 0, 0, 1000, 1000 );
        CharacterRange[] ranges = { new CharacterRange ( 0, text.Length ) };
        Region[] regions = new Region[1];

        format.SetMeasurableCharacterRanges ( ranges );
        format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;

        regions = graphics.MeasureCharacterRanges ( text, font, rect, format );
        rect = regions[0].GetBounds ( graphics );

        return (int)( rect.Right );
    }

Measuring text widths can be a nighmare.. I dont know why they made it so confusing..

Heres the most accurate way Ive got to measure the length of text :

    protected int _MeasureDisplayStringWidth ( Graphics graphics, string text, Font font )
    {
        if ( text == "" )
            return 0;

        StringFormat format = new StringFormat ( StringFormat.GenericDefault );
        RectangleF rect = new RectangleF ( 0, 0, 1000, 1000 );
        CharacterRange[] ranges = { new CharacterRange ( 0, text.Length ) };
        Region[] regions = new Region[1];

        format.SetMeasurableCharacterRanges ( ranges );
        format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;

        regions = graphics.MeasureCharacterRanges ( text, font, rect, format );
        rect = regions[0].GetBounds ( graphics );

        return (int)( rect.Right );
    }
画▽骨i 2024-08-20 01:24:48

我不能 100% 确定这就是您真正需要的。

但您可能想看看这个 Microsoft 页面:

I am not 100% sure it is what you exactly need.

But you may want to have a look at this Microsoft page:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文