The rusttype repo contains an example (examples/image.rs), which measures the bounds of a line of text and renders it to an image. Basically what you're searching, besides the centering part.
// rusttype = "0.9.2"
use rusttype::{point, Font, Scale};
let v_metrics = font.v_metrics(scale);
let glyphs: Vec<_> = font.layout(text, scale, point(0.0, 0.0)).collect();
let glyphs_height = (v_metrics.ascent - v_metrics.descent).ceil() as u32;
let glyphs_width = {
let min_x = glyphs
.first()
.map(|g| g.pixel_bounding_box().unwrap().min.x)
.unwrap();
let max_x = glyphs
.last()
.map(|g| g.pixel_bounding_box().unwrap().max.x)
.unwrap();
(max_x - min_x) as u32
};
I didn't like always needing to collect into a Vec, while also needing to use non-integer sizes. So in the past I created my own version of what's essentially in the example.
One important note, is that the position passed to layout doesn't really matter, when you only need the size. However, if you actually need to render the glyphs, then the position is important as otherwise the result will contain aliasing artifacts.
// rusttype = "0.9.2"
use rusttype::{point, Font, Scale};
fn measure_line(font: &Font, text: &str, scale: Scale) -> (f32, f32) {
let width = font
.layout(text, scale, point(0.0, 0.0))
.map(|g| g.position().x + g.unpositioned().h_metrics().advance_width)
.last()
.unwrap_or(0.0);
let v_metrics = font.v_metrics(scale);
let height = v_metrics.ascent - v_metrics.descent + v_metrics.line_gap;
(width, height)
}
If the text has multiple lines, then you'd manually need to use .lines() on the string, and then sum the line heights and line spacing.