I'm trying to use the rusttype crate to render text. So far it's been fantastic, but I am running into a wall when trying to correctly position individual glyphs.
I am rendering text by rendering each glyph to an RgbaImage
(from the image crate, like in the rusttype
image example) and rendering it to a quad mesh.
pub struct Glyph {
pub image: image::RgbaImage,
pub glyph: rusttype::PositionedGlyph<'static>,
pub vertical_offset: f32,
}
// &self.font is a rusttype::Font type
pub fn draw_glyph(&self, ch: char, font_size: f32) -> Option<Glyph> {
// Set size
let scale = rusttype::Scale::uniform(font_size);
let v_metrics = self.font.v_metrics(scale);
// Position and scale glyph
let offset = rusttype::point(0.0, 0.0 + v_metrics.ascent);
let glyph = self.font.glyph(ch).scaled(scale).positioned(offset);
// Get glyph dimensions
let bounds = glyph.pixel_bounding_box()?;
let glyph_height = (v_metrics.ascent - v_metrics.descent).ceil() as u32;
let glyph_width = (bounds.max.x - bounds.min.x) as u32;
// Try to align glyphs on a baseline
let offset_y = bounds.height() as f32 - v_metrics.ascent;
// Generate image
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,
})
}
However, without the vertical_offset
calculation, I receive the following text:
As you can see, the characters are all over the place.
I need to take into account the ascent
and descent
size of the font. However, this is where I run into issues.
I can compensate for the ascent
using the following calculation:
let bounds = glyph.pixel_bounding_box()?;
let offset_y = bounds.height() as f32 - v_metrics.ascent;
And then shifting the quad meshes downwards by offset_y
.
This improves the output when there are no descenders like "g" in the text:
But does not help when there are descending characters involved:
I cannot figure out how the rusttype
examples handle this. They use the Font::layout
method, but this doesn't have any special vertical align code.
I'm definitely doing something wrong. Please help!
Try compensating for the descent as well: