使用rusttype库渲染文本时如何正确垂直定位单个字形?
问题根源
你的垂直偏移计算逻辑忽略了单个字形像素边界盒的min.y参数,且为单个字形分配的画布高度使用了全局字体行高,二者共同导致了对齐错乱:
- rusttype中每个字形的
pixel_bounding_box()返回的边界盒坐标是相对布局坐标系的(y轴向下为正),min.y就是字形像素区域顶部相对于坐标系原点的垂直偏移,不同字形的这个值差异很大,不能仅用全局的ascent推导 - 你当前为单个字形创建的
RgbaImage高度用了全局的ascent - descent(整行高度),会给没有填满整行的字形引入多余的顶部空白,放大偏移误差
修正方案
按以下逻辑调整代码即可:
- 字形画布的宽高直接用边界盒自身的宽高,不用全局行高
vertical_offset直接取值为边界盒的min.y,渲染四边形时直接按这个值做垂直偏移即可
修正后的核心代码如下:
pub struct Glyph { pub image: image::RgbaImage, pub glyph: rusttype::PositionedGlyph<'static>, pub vertical_offset: f32, // 可选添加水平偏移,用于字符间距调整 pub horizontal_offset: f32, } // &self.font是rusttype::Font类型的实例 pub fn draw_glyph(&self, ch: char, font_size: f32) -> Option<Glyph> { // 设置字号 let scale = rusttype::Scale::uniform(font_size); let v_metrics = self.font.v_metrics(scale); // 定位并缩放字形 let offset = rusttype::point(0.0, v_metrics.ascent); let glyph = self.font.glyph(ch).scaled(scale).positioned(offset); // 获取字形尺寸 let bounds = glyph.pixel_bounding_box()?; // 直接用边界盒自身的宽高作为画布尺寸 let glyph_height = (bounds.max.y - bounds.min.y) as u32; let glyph_width = (bounds.max.x - bounds.min.x) as u32; // 直接取边界盒的min.y作为垂直偏移,不需要额外计算 let offset_y = bounds.min.y as f32; // 水平偏移可选添加,用于后续字符排版 let offset_x = bounds.min.x as f32; // 生成字形图像 let mut image = image::ImageBuffer::from_pixel(glyph_width, glyph_height, image::Rgba([200; 4])); glyph.draw(|x, y, v| { image.put_pixel(x, y, image::Rgba([0 + (v * 255.0) as u8; 4])); }); Some(Glyph { glyph: glyph, image: image, vertical_offset: offset_y, horizontal_offset: offset_x, }) }
排版注意事项
渲染多个连续字符时,每个字符的水平位置需要叠加前一个字符的h_metrics().advance_width,所有字符的垂直对齐都以统一的基线为基准,配合上面计算的vertical_offset即可实现全行字符对齐。
内容的提问来源于stack exchange,提问作者haz
相关产品推荐
相关产品推荐

