如何使用DrawText查找在Windows中呈现的文本的精确像素高度

时间:2015-03-17 13:54:05

标签: c++ windows gdi

我希望找到在Windows中呈现的文本的确切高度。我已尝试使用GetTextExtentPoint32并使用DT_CALCRECT标志调用DrawText,两者都给出了相同的结果。

似乎返回的高度基于完整的单元格高度,无论要绘制的实际文本如何。

以下代码是标准Visual Studio 2013 Win32项目的WM_PAINT处理程序。它创建一个(大)字体并绘制示例文本。文本的最高部分是98像素,但GetTextExtentPoint32返回的值是131.

我意识到某些应用程序可能需要完整的单元格高度,但某些应用程序(如我的)只需要文本使用的实际高度。

有谁知道如何找到这些信息?

是的,我可以渲染到内存DC并向下扫描,寻找第一个非背景彩色像素 - 但这将是超级慢的。

由于

case WM_PAINT:
{
    hdc = BeginPaint (hWnd, &ps);

    HFONT hfont = CreateFont (-99, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH, L"Segoe UI Semibold");
    auto old_hfont = SelectObject (hdc, hfont);

    wchar_t sample_text[] = L"123 Testing 123";
    size_t sample_text_length = wcslen (sample_text);

    SIZE s;
    GetTextExtentPoint32 (hdc, sample_text, sample_text_length, &s);

    RECT r = {10, 10, 10 + s.cx, 10 + s.cy};

    SetBkColor   (hdc, RGB (80, 120, 160));
    SetTextColor (hdc, RGB (220, 220, 220));

    DrawText (hdc, sample_text, sample_text_length, &r, DT_SINGLELINE | DT_NOPREFIX | DT_LEFT | DT_TOP);

    SelectObject (hdc, old_hfont);
    DeleteObject (hfont);

    EndPaint (hWnd, &ps);
    break;
}

4 个答案:

答案 0 :(得分:7)

看看GetGlyphOutline(GGO_METRICS) 返回的GLYPHMETRICS结构应包含计算范围所需的所有数据。

答案 1 :(得分:4)

您的文字不是直接绘制的,首先他变成了path,它描述了几何/字形的轮廓。路径由移动,线条和曲线(以及前一个的关闭标志)组成。除曲线外,其他路径段是最终填充的极值点。将曲线转换为线并迭代所有路径段以找到水平线和/或线的最小值和最大值。点的垂直尺寸会导致与文本最接近的拟合矩形。

您可以通过在之前和BeginPath之后调用EndPath来绘制文本,将文本转换为路径。 FlattenPath执行curve->行转换。 GetPath提供对上下文路径点的访问。 AbortPath最终从上下文中删除了路径。

当你没有set the background to transparent时,路径可能是文本周围的背景,并且第一个路径段已经是背景/范围矩形线 - 而不是你想要的。

为了简化此方法,您可以将重复字符和组字符排除在1)以下基线2)以上中线3)之外。与您的"外观像素相比,这一切都非常快速地工作。尝试。

有关文字大小的其他有用来源是font metricsGetTextMetrics)和character widthsGetCharABCWidths

答案 2 :(得分:3)

如果您的示例文本仅包含ASCII字母,则可以手动评估升序字母的高度,如b,降序字母为g,中间字母为x。你可以提前做一次,甚至可能离线,所以任何效率低下的方法都很好。

然后(取决于字体到一小部分误差)计算整体高度是对ascenders(bdfhijkltA-Z)和下行(gjpqy)的简单检查你的字符串。

答案 3 :(得分:2)

如果这是TrueType字体,您可以找到字形定位的大小w.r.t. fmtx表中的'上一个'字母和行,如here所述。还有similar information可用于OpenType字体,但导出有意义的东西看起来更麻烦。

这并没有给出字形的实际像素大小,但它确实可以让您更准确地了解特定字形的真实字体路径与“基线”相关的位置,以及单位使用磅值进行缩放并且是字体范围的。

在你的情况下,我会看看FreeType,这是一个快速的第三方库,支持光栅字体,TrueType和OpenType字体。它被广泛使用且非常well documented并受到支持,可以提供准确的指标。