Looking for a complete answer that provides rust code (with any crate) for exactly calculating the pixel width of a string of text, for any font.Current answers provide estimations, or do not account for certain issues such as kerning and use of text scenarios such as emojis.
我正在撰写一项功能,其文字载体、字面字体字迹、字体直面价值和线带宽度等值。
目的是撰写一份<代码><text> tag to an SVG,但如果该指示数将超过直线字母顺序,则该功能将撰写多部<text>
tags(具有适当的功能)从而使最终结果成为多线指示。
The problem I m facing is finding a crate that will parse the TTF file, and then provide me the pixel length of a chunk of text.
I ve tried looking at the ttf-parser library, with the following sample code, but to no avail (the output crashes when coming across a space character, and also the width it calculates give huge pixel values which I think is not correct.
我知道有像宇宙文本这样的非专业图书馆,但我无法理解我如何利用这些图书馆来衡量简单案文的层面,更不用说执行布局和总结。
use ttf_parser as ttf;
use anyhow::{anyhow, Context};
// Okay this one tries using the ttf_parser crate
pub fn get_text_width(
text: &str,
font_size: f32,
font_family: &str,
ttf_path: &str,
) -> Result<f32, anyhow::Error> {
// okay we need to use the ttf-parser lib to calculate the width of the text
// and in this will output the width in pixels of the text
// so we can, in other code, figure out if we need to wrap text into a newline
// Loads the font file as bytes
let font_data = std::fs::read(ttf_path).context("Failed to read ttf file")?;
// Parses the font file
let mut face = ttf::Face::parse(&font_data, 0).context("Failed to parse ttf file into face")?;
// https://fonts.google.com/knowledge/glossary/em
// An em is a unit of measurement, relative to the size of the font; therefore, in a typeface set at a font-size of 16px, one em is 16px.
let units_per_em = face.units_per_em();
let scale = font_size / units_per_em as f32;
let mut delta_x = 0_i16; // this is supposed to be the total horizontal space occupied by the string, in pixels
let char = text.chars().next().unwrap();
let glyph_id = face.glyph_index(char).unwrap();
let horizontal_advance = face.glyph_hor_advance(glyph_id).unwrap();
let bounding_box = face.glyph_bounding_box(glyph_id).unwrap();
for char in text.chars() {
println!("char: {}", char);
let glyph_id = face.glyph_index(char).unwrap();
println!("Glyph id: {}", glyph_id.0);
let bounding_box = face.glyph_bounding_box(glyph_id).context(format!("Failed to get bounding box for glyph: {char}"))?;
// Something s wrong here, the numbers are large. So this can t be in pixels, right?
println!("Bounding box: {}", bounding_box.width());
println!("Horizontal advance: {}", face.glyph_hor_advance(glyph_id).unwrap());
delta_x += bounding_box.width();
}
let to_return = delta_x * scale as i16;
Ok(to_return as f32)
}