测量.net图形中文本的实际高度

测量.net图形中文本的实际高度,.net,winforms,graphics,system.drawing,.net,Winforms,Graphics,System.drawing,背景:我正在尝试使用Cambria数学字体呈现一些文本。为了正确定位和缩放它,我需要测量文本。但是,Graphics.MeasureString和Graphics.MeasureCharacterRanges似乎都返回字体的FontMetrics中定义的文本的行高,而不管要呈现的实际文本是什么。例如,如果我测量一个简单的单个字符,比如“x”,据报道它的高度是宽度的近8倍 这种特殊的字体有非常大的上升、下降和线条高度,大概是因为它包含一些非常高的不寻常的符号。(此字体的FontMetrics.Ge

背景:我正在尝试使用Cambria数学字体呈现一些文本。为了正确定位和缩放它,我需要测量文本。但是,Graphics.MeasureString和Graphics.MeasureCharacterRanges似乎都返回字体的FontMetrics中定义的文本的行高,而不管要呈现的实际文本是什么。例如,如果我测量一个简单的单个字符,比如“x”,据报道它的高度是宽度的近8倍

这种特殊的字体有非常大的上升、下降和线条高度,大概是因为它包含一些非常高的不寻常的符号。(此字体的FontMetrics.GetLineHeight为11428,而我测试的随机典型字体的FontMetrics.GetLineHeight为2318。两者的GetEmHeight均为2048)

在Win7中的字符映射应用程序中可以看到这种效果:如果选择Cambria数学字体,并选择一个字符,它会在选择框中显示为一个大点-可能它已缩放到自然大小的15%左右,以使理论线高度适合框


问题是:有没有一种方法可以测量特定字符串的实际高度,在这种情况下,它会给我一个更有意义的高度?实际上,我不会渲染任何异常高大的角色

我知道这是一年前发布的,假设你要么没有发布答案就修复了,要么就放弃了

总之,这是我刚刚写的一些代码。背线字符串就是这样,我有带“drop”(j和g)的字母,还有一些是最高的(我想大多数字体都有大写字母)

结果是以像素为单位的大小,然后需要使用所需的任何设备分辨率进行缩放

    Dim tmpfont As Font = New Font(FontFamily.GenericSansSerif, 32)

    Dim supportedcharheight As String = "TKjg,'"
    Dim tmpsize As SizeF = _labelcanvas.MeasureString(supportedcharheight, tmpfont)
    Dim b As Bitmap = New Bitmap(tmpsize.Width, tmpsize.Height)

    Dim g As Graphics = Graphics.FromImage(b)
    g.FillRectangle(Brushes.White, 0, 0, b.Width, b.Height)
    g.DrawString(supportedcharheight, tmpfont, Brushes.Black, 0, 0)
    g.Dispose()

    Dim d As Drawing.Imaging.BitmapData = b.LockBits(New Rectangle(0, 0, b.Width, b.Height), Imaging.ImageLockMode.ReadWrite, Imaging.PixelFormat.Format32bppArgb)


    Dim pixel(3) As Byte
    Dim rowptr As IntPtr
    Dim pixptr As IntPtr

    Dim toprow As Integer = b.Height
    Dim bottomrow As Integer = 0
    Dim foundpix As Boolean = False

    For y As Integer = 0 To b.Height - 1
        rowptr = d.Scan0 + (y * d.Stride)
        For x As Integer = 0 To b.Width - 1
            pixptr = rowptr + (x * 4)
            Runtime.InteropServices.Marshal.Copy(pixptr, pixel, 0, 4)
            If pixel(0) < 255 Then
                If toprow > y Then toprow = y
                If bottomrow < y Then bottomrow = y
                Exit For
            End If
        Next
    Next

    b.UnlockBits(d)
    b.Dispose()

    Dim actualpixels As Integer = bottomrow - toprow
Dim tmpfont As Font=新字体(FontFamily.GenericSansSerif,32)
支持的尺寸字符高度为String=“TKjg,”
Dim tmpsize As SizeF=_labelcanvas.MeasureString(支持字符高度,tmpfont)
作为位图的尺寸b=新位图(tmpsize.Width、tmpsize.Height)
尺寸g为图形=图形。来自图像(b)
g、 圆角矩形(画笔。白色,0,0,b.宽度,b.高度)
g、 抽绳(支持的字符高度,tmpfont,画笔。黑色,0,0)
g、 处置
尺寸d为Drawing.Imaging.BitmapData=b.LockBits(新矩形(0,0,b.宽度,b.高度),Imaging.ImageLockMode.ReadWrite,Imaging.PixelFormat.Format32bppArgb)
变暗像素(3)作为字节
变暗rowptr为IntPtr
作为IntPtr的Dim pixptr
Dim toprow作为整数=b.高度
作为整数的Dim BOTTROW=0
将foundpix设置为布尔值=False
对于y,作为整数=0到b。高度-1
rowptr=d.Scan0+(y*d.Stride)
对于x,作为整数=0到b。宽度-1
pixptr=rowptr+(x*4)
Runtime.InteropServices.Marshal.Copy(pixptr,pixel,0,4)
如果像素(0)<255,则
如果toprow>y,则toprow=y
如果bottomrow
Marq的答案促使我用另一种测量字符的方法来回答,这种方法我在其他地方使用过,可能更有效。可以使用FontFamily(而不是Font!)对象获取字符串的完整路径数据。从中可以很容易地获得准确的指标:

Dim path As New Drawing2D.GraphicsPath
path.AddString(myText, myFontFamily,....)
Dim textSize As SizeF = path.GetBounds.Size

它测量实际字符占用的确切大小。通过使用AddString中的布局矩形,您还可以测量4条边上的死区,等等。

不确定这条线的相关性吗?我知道,对于这种字体来说,单元格的上升幅度是巨大的——这就是问题所在——它比字体中几乎所有字符的视觉上升幅度大好几倍。我正在寻找一个不使用FontFamily中令人误解的升序和降序的特定字符的度量值。可能重复的感谢我没有看到这个-我搜索的是度量值问题,而不是字体名称。这是相同的问题,但有点不同的问题-他想将字体分配给WinForms控件,而如果我可以测量给定的字符集,我就可以正确渲染。我怀疑“你不能”的答案可能是一样的。谢谢你的答案,值得投一票。我确实解决了这个问题——只需对字体的高度应用一个修正系数。这听起来像是一个可怕的乱七八糟;但事实上,度量返回的高度对于给定字体是固定的。我只是用一个更有用的值替换了该特定字体的误导性值。(大致除以5)。这对我来说很管用,因为字体主要包含“普通”字符和一些我无论如何都不会绘制的超高字符。我会用我发现的另一种方法添加答案。。。