确定指定字体的确切字形高度

我经常搜索并尝试了很多,但我找不到合适的解决方案。

我想知道有没有办法确定指定字体的确切字形高度

我的意思是在这里,当我想确定DOT字形的高度时,我应该收到较小的高度而不是带有填充或字体大小的高度。

我已经找到了确定精确字形宽度的解决方案(我已经使用了第二种方法),但它不适用于高度。

更新:我需要.NET 1.1的解决方案

获得角色指标并不难。 GDI包含一个函数GetGlyphOutline ,您可以使用GGO_METRICS常量调用该GGO_METRICS来获取渲染时包含字形所需的最小包围矩形的高度和宽度。 即,字体Arial中的点的10点字形将给出1×1像素的矩形,如果字体是100磅,则为字母I 95x.14。

这些是P / Invoke调用的声明:

 // the declarations public struct FIXED { public short fract; public short value; } public struct MAT2 { [MarshalAs(UnmanagedType.Struct)] public FIXED eM11; [MarshalAs(UnmanagedType.Struct)] public FIXED eM12; [MarshalAs(UnmanagedType.Struct)] public FIXED eM21; [MarshalAs(UnmanagedType.Struct)] public FIXED eM22; } [StructLayout(LayoutKind.Sequential)] public struct POINT { public int x; public int y; } [StructLayout(LayoutKind.Sequential)] public struct POINTFX { [MarshalAs(UnmanagedType.Struct)] public FIXED x; [MarshalAs(UnmanagedType.Struct)] public FIXED y; } [StructLayout(LayoutKind.Sequential)] public struct GLYPHMETRICS { public int gmBlackBoxX; public int gmBlackBoxY; [MarshalAs(UnmanagedType.Struct)] public POINT gmptGlyphOrigin; [MarshalAs(UnmanagedType.Struct)] public POINTFX gmptfxGlyphOrigin; public short gmCellIncX; public short gmCellIncY; } private const int GGO_METRICS = 0; private const uint GDI_ERROR = 0xFFFFFFFF; [DllImport("gdi32.dll")] static extern uint GetGlyphOutline(IntPtr hdc, uint uChar, uint uFormat, out GLYPHMETRICS lpgm, uint cbBuffer, IntPtr lpvBuffer, ref MAT2 lpmat2); [DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)] static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj); 

如果您不考虑P / Invoke冗余,那么实际代码相当简单。 我测试了代码,它可以工作(您可以调整以获得GLYPHMETRICS的宽度)。

注意:这是ad-hoc代码,在现实世界中,您应该使用ReleaseHandleDeleteObject清理HDC和对象。 感谢user2173353的评论指出这一点。

 // if you want exact metrics, use a high font size and divide the result // otherwise, the resulting rectangle is rounded to nearest int private int GetGlyphHeight(char letter, string fontName, float fontPointSize) { // init the font. Probably better to do this outside this function for performance Font font = new Font(new FontFamily(fontName), fontPointSize); GLYPHMETRICS metrics; // identity matrix, required MAT2 matrix = new MAT2 { eM11 = {value = 1}, eM12 = {value = 0}, eM21 = {value = 0}, eM22 = {value = 1} }; // HDC needed, we use a bitmap using(Bitmap b = new Bitmap(1,1)) using (Graphics g = Graphics.FromImage(b)) { IntPtr hdc = g.GetHdc(); IntPtr prev = SelectObject(hdc, font.ToHfont()); uint retVal = GetGlyphOutline( /* handle to DC */ hdc, /* the char/glyph */ letter, /* format param */ GGO_METRICS, /* glyph-metrics */ out metrics, /* buffer, ignore */ 0, /* buffer, ignore */ IntPtr.Zero, /* trans-matrix */ ref matrix); if(retVal == GDI_ERROR) { // something went wrong. Raise your own error here, // or just silently ignore return 0; } // return the height of the smallest rectangle containing the glyph return metrics.gmBlackBoxY; } } 

您能否更新问题以包括您尝试过的内容?

用点字形我假设你的意思是这里详述的标点符号?

这个字形高度是显示在屏幕还是打印页面上?

我设法修改你发布的链接中的第一个方法,以便计算匹配的垂直像素,但是除非你愿意逐个字符地绘制,否则识别字形的最大高度是很繁琐的,所以这不是真的像文章一般的工作解决方案。

为了获得一般的工作解决方案,需要识别字符/字形的最大单个像素垂直区域,然后计算该区域中的像素数。

我还设法validationGraphics.MeasureStringTextRenderer.MeasureTextGraphics.MeasureCharacterRanges都返回了一个边界框,它给出了一个类似于字体高度的数字。

替代方法是使用Glyph.ActualHeight属性获取框架元素的渲染高度。 这部分WPF和相关的GlyphTypefaceGlyphRun类。 此时只有Mono,我无法测试它们。

获取Glyph.ActualHeight的步骤如下

  1. 初始化GlyphRun的参数

  2. 初始化GlyphRun对象

  3. 使用glyphTypeface.CharacterToGlyphMap[text[n]]或更准确地访问相关的Glyph glyphTypeface.GlyphIndices[n] ,其中glyphTypeface是您的GlyphTypeface,它是根据您在步骤1中创建的Typeface对象创建的。

使用它们的相关资源包括

  • 关于雕文的事情
  • GlyphRun和So Forth
  • 测量文本
  • 字形特别是底部的图片。

关于GDI的更多参考(这些类在引擎盖下使用的是GDI或GDI +)和Windows中的字体包括

  • GDI
  • Windows字体映射

这是一个涉及WPF的解决方案。 我们创建一个中间Geometry对象,以便检索文本的准确边界框。 这种解决方案的优点是它实际上不会渲染任何东西。 即使您没有为界面使用WPF,也可以使用这段代码进行测量,假设字体渲染大小在GDI中相同,或者足够接近。

  var fontFamily = new FontFamily("Arial"); var typeface = new Typeface(fontFamily, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal); var fontSize = 15; var formattedText = new FormattedText( "Hello World", CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, fontSize, Brushes.Black); var textGeometry = formattedText.BuildGeometry(new Point(0, 0)); double x = textGeometry.Bounds.Left; double y = textGeometry.Bounds.Right; double width = textGeometry.Bounds.Width; double height = textGeometry.Bounds.Height; 

这里,“Hello world”测量值约为77 x 11单位。 单点给出1.5 x 1.5。

作为替代解决方案,仍然在WPF中,您可以使用GlyphRun和ComputeInkBoundingBox()。 但它有点复杂,不支持自动字体替换。 它看起来像这样:

 var glyphRun = new GlyphRun(glyphTypeFace, 0, false, fontSize, glyphIndexList, new Point(0, 0), advanceWidths, null, null, null, null, null, null); Rect glyphInkBox = glyphRun.ComputeInkBoundingBox();