求助:FreeType2中指定字号字体高度的正确计算方法
先得明确你要的是哪种“字体高度”——不同场景下的定义差异,正是你原公式失效的核心原因。下面分三种常见场景给出对应的正确计算方式:
1. 字体设计的标称高度(不含行间距)
如果你的需求是字体设计时定义的、从最高上升部到最低下降部的标称高度(大部分常规排版场景里的“字体高度”指这个),原公式本身逻辑没问题,但要注意避免整数除法的精度丢失——把units_per_EM转成浮点数再计算:
// 标称高度:设计定义的上下总高度(不含行间距) int nominal_height = (int)((point_size / (double)face->units_per_EM) * (face->ascender - face->descender));
不过这个公式对部分字体失效,是因为有些字体(比如手写体、装饰字体)的实际字形会超出ascender和descender的设计范围,这时候你需要的是所有字形的实际最大高度。
2. 所有字形实际占据的最大垂直高度
如果要确保覆盖字体中所有字形的实际垂直范围(避免某些特殊字形被截断),应该用字体的全局边界框来计算:
// 实际最大高度:包含所有字形的上下极限 int actual_max_height = (int)((point_size / (double)face->units_per_EM) * (face->bbox.yMax - face->bbox.yMin));
这里face->bbox.yMax是所有字形里的最高点(基于EM坐标),face->bbox.yMin是最低点,两者差值就是字体实际占据的垂直总范围,转换成指定字号后就是你需要的高度。
3. 排版时的推荐行高
如果你的需求是排版时每行的完整高度(包含行间距),直接用FreeType提供的face->height字段即可:
// 推荐行高:标称高度 + 设计推荐的行间距 int line_height = (int)((point_size / (double)face->units_per_EM) * face->height);
face->height的定义是ascender - descender + line_gap,是字体设计师推荐的行间距,适合常规段落排版。
补充说明
原公式的另一个潜在问题是整数除法:如果point_size和face->units_per_EM都是整数,point_size / face->units_per_EM会先执行整数除法,导致精度丢失。转换成浮点数计算可以避免这个问题,让结果更准确。
内容的提问来源于stack exchange,提问作者Karthik Kubendiran

