【问题标题】:Measuring the actual height of text in .net graphics测量 .net 图形中文本的实际高度
【发布时间】:2016-03-15 00:12:24
【问题描述】:

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

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

这样的效果可以在Win7中的Character map应用程序中看到:如果你选择Cambria Math字体,然后选择一个字符,它在选择框中显示为一个大点——大概它已经被缩放到了15%左右自然大小以使理论线高适合盒子。

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

【问题讨论】:

  • 不确定那个汉斯的相关性?我知道这种字体的单元格上升是巨大的——这就是问题所在——它比字体中几乎所有字符的视觉上升要大几倍。我正在寻找特定字符的度量,这些字符使用 FontFamily 的误导性上升和下降。
  • 谢谢我没有看到那个 - 我搜索的是测量问题而不是字体名称。这是同样的问题,但有些不同的问题 - 他想将字体分配给 WinForms 控件,而如果我可以测量给定的一组字符,我就可以正确渲染。我怀疑答案——“你不能”——可能是一样的。

标签: .net winforms graphics system.drawing


【解决方案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

【讨论】:

  • 感谢您的回答,值得一票。我确实已经解决了它 - 只需将校正因子应用于该字体的高度。这听起来像是一个可怕的混搭。但实际上 MeasureString 返回的高度对于给定字体是固定的。我只是用更有用的值替换了该特定字体的误导值。 (大致除以 5)。这对我有用,因为字体主要包含“普通”字符和一些我无论如何都不会绘制的超高字符。我会用我也找到的另一种方法添加答案...
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多