首页 > 解决方案 > 获取由 DrawText[Ex] 解释的 GDI HFONT 行高

问题描述

我想知道哪些指标用于计算正确的行高(2 个相邻文本行的基线之间的垂直距离)。“正确”应任意定义为“无论做什么DrawTextW”。

此处接受的答案似乎遵循此 MSDN 文章中提供的图表所说的内容:

TEXTMETRICW.tmHeight + TEXTMETRICW.tmExternalLeading;

但这似乎并不正确。使用 2 段文本进行一些测试,每段文本由 2 行组成:

// RECT rc is more than large enough to fit any text
int HeightChinese = DrawTextW(hdc, L"中\r\n文", -1, &rc, 0);
int HeightLatin = DrawTextW(hdc, L"Latin,\r\nlatin!", -1, &rc, 0);

预期的返回值应该是2 * <SomethingUnknown>.

一个观察结果是,对于我机器上的所有字体,如果使用的话,返回值DrawTextW将始终与RECT输出匹配。DT_CALCRECT所以我会假设 usingDT_CALCRECT不会提供任何额外的价值,而不是使用DrawTextW.

对于我机器上的所有字体,这些都是正确的:

对于我机器上的大多数字体,这是真的:

这已经与另一个问题中提供的公式相矛盾TEXTMETRICW.tmExternalLeading不起作用)。

例如,带有 , 和(不是 74)的“ LOGFONTW.lfHeight = 36Arial TEXTMETRICW.tmExternalLeading = 1HeightXxx == 72。截屏并测量像素时,线之间的距离也是 72(因此看起来返回值可以信任)。

同时,“Segoe UI”带有LOGFONTW.lHeight = 43,TEXTMETRICW.tmExternalLeading = 0HeightXxx == 84(不是 86)。

这是我系统上所有异常字体的列表:

"FontName" -- "DrawText return value" vs "2 * TEXTMETRICW.tmHeight"

Ebrima -- 84 vs 86
Leelawadee UI -- 84 vs 86
Leelawadee UI Semilight -- 84 vs 86
Lucida Sans Unicode -- 96 vs 98
Malgun Gothic -- 84 vs 86
Malgun Gothic Semilight -- 84 vs 86
Microsoft Tai Le -- 80 vs 82
Microsoft YaHei -- 82 vs 84
Microsoft YaHei UI Light -- 82 vs 84
MS Gothic -- 66 vs 64
MS UI Gothic -- 66 vs 64
MS PGothic -- 66 vs 64
Nirmala UI -- 84 vs 86
Nirmala UI Semilight -- 84 vs 86
Palatino Linotype -- 84 vs 86
Segoe UI -- 84 vs 86
Segoe UI Black -- 84 vs 86
Segoe UI Historic -- 84 vs 86
Segoe UI Light -- 84 vs 86
Segoe UI Semibold -- 84 vs 86
Segoe UI Semilight -- 84 vs 86
Segoe UI Symbol -- 84 vs 86
SimSun -- 66 vs 64
NSimSun -- 66 vs 64
SimSun-ExtB -- 66 vs 64
Verdana -- 76 vs 78
Webdings -- 62 vs 64
Yu Gothic UI -- 84 vs 86
Yu Gothic UI Semibold -- 84 vs 86
Yu Gothic UI Light -- 84 vs 86
Yu Gothic UI Semilight -- 84 vs 86
MS Mincho -- 66 vs 64
MS PMincho -- 66 vs 64
Ubuntu Mono -- 62 vs 64

有时返回值比计算值大 2,有时比计算值小 2。

我查看了 中的其他值TEXTMETRICW,还查看了可用的额外数据 int OUTLINETEXTMETRICW,但我找不到任何可以解释观察结果的模式。

那么,计算线高的正确指标是什么?我知道我可以调用DrawTextWwithDT_CALCRECT来获取这个值,但我想了解这些信息的来源(以及字体设计师如何以可预测的方式控制它)。

这是一个带有完整 Windows 应用程序的要点,它演示了这一点。所有有趣的东西都在WM_PAINT. 搜索@EDIT一些有趣的代码切换和断点。在发布此问题时,我的 GitHub 帐户已被标记,并且 Gist 暂时不可用。我希望这可以很快得到解决。

(1)EnumFontFamiliesEx用来枚举所有字体,它恰好为LOGFONTW结构提供了正值 lfHeight。这意味着我使用的是单元格高度而不是字符高度。虽然字符高度是指定字体高度的更典型方式,但在这里有点无关紧要,碰巧单元格高度等于TEXTMETRICW.tmHeight,但字符高度不是。计算的相关值是TEXTMETRICW.tmHeight,而不是LOGFONTW.lfHeight

标签: windowswinapifontsgdi

解决方案


DrawText()仅在您调用它时设置TEXTMETRIC.tmExternalLeadingDT_EXTERNALLEADING标志时使用 - 您似乎没有考虑到这一点。

线高公式基本上是:

int iLineHeight = tm.tmHeight + ((format & DT_EXTERNALLEADING) ? tm.tmExternalLeading : 0);

推荐阅读