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

时间:2015-02-02 18:18:26

标签: .net winforms graphics system.drawing

背景:我正在尝试使用Cambria Math字体渲染一些文本。为了正确定位和缩放它我需要测量文本。但是,无论要呈现的实际文本如何,Graphics.MeasureString和Graphics.MeasureCharacterRanges似乎都返回FontMetrics中为字体定义的文本的行高。例如,如果我测量一个简单的单个字符,例如" x",据报道它的宽度几乎是它的8倍。

这个特殊的字体具有非常大的上升,下降和行高,可能是因为它包含一些非常高的异常符号。 (对于这种字体,FontMetrics.GetLineHeight为11428,而我测试的随机,典型字体为2318.两者都有GetEmHeight = 2048)。

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

问题:有没有办法测量特定字符串的实际高度,在这种情况下,这会给我一个更有意义的高度?在实践中,我不会渲染任何异常高的角色。

2 个答案:

答案 0 :(得分:1)

我知道这是在一年前发布的,并且假设您已修复但没有发布您的答案或放弃。

无论如何,这是我刚才写的一些代码。顶线字符串就是这样,我已经收到了带有" 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

答案 1 :(得分:1)

Marq的回答促使我回答了另一种测量我曾在其他地方使用过的字符的方法,这可能更有效率。可以使用FontFamily(而不是Font!)对象获取字符串的完整路径数据。从中可以轻松获得准确的指标:

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

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