Rust:如何确定文本字符串的像素宽度?

问题描述 投票:0回答:1

我正在编写一个函数,它接受一个文本字符串、一个 .ttf 字体文件路径、一个 fontsize int 值和一个 linewidthinpixels int 值。

目标是将标签写入 SVG,但如果字符串超出像素线宽,则该函数将写入多个标签(具有适当的 dy 属性),以便最终结果将是多行字符串。

我面临的问题是找到一个可以解析 TTF 文件的包,然后为我提供一段文本的像素长度。

我尝试使用以下示例代码查看 ttf-parser 库,但无济于事(遇到空格字符时输出崩溃,而且它计算的宽度给出了巨大的像素值,我认为这是不正确的.

我知道有像 cosmic-text 这样的布局库,但我一生都无法理解如何使用它们来测量简单文本字符串的尺寸,更不用说实现布局和换行了。

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)
}
user-interface rust fonts
1个回答
0
投票

这是我在一个需要我估计文本大小的项目中所做的:

use rusttype::Font;
use rusttype::Scale;

let fs = 64.0;
let font_data: &[u8] = include_bytes!("/usr/share/fonts/noto/NotoSans-Bold.ttf");
let font: Font = Font::try_from_bytes(font_data).unwrap();
let gw = fonts
            .glyph('W')
            .scaled(Scale::uniform(fs))
            .h_metrics()
            .advance_width as i32;
let fvm = font.v_metrics(Scale::uniform(fs));
let gh = (fvm.descent.abs() - fvm.ascent.abs()) as i32;
let width = gw * text_length;
let height = gh * line_count;
© www.soinside.com 2019 - 2024. All rights reserved.