English 中文(简体)
我如何确定案文的顺序?
原标题:How do I determine the pixel width of a string of text?
The bounty expires in 10 hours. Answers to this question are eligible for a +50 reputation bounty. Shazamo Morebucks wants to draw more attention to this question:
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)
}
问题回答

TLDR: use rusttype library.

在此,我在一个需要我估计案文规模的项目中做了些什么:

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;

显然,这大致如此。 确切的衡量,你将逐条分析,而不仅仅是逐字逐句增加一些内容。

为了更准确地估计案文的大小,你需要考虑构成您案文的每一种精华的个人层面,因为不同的特性有不同的宽度,甚至在单一空间体内也是如此。 此外,跟踪(所有特性之间的间隔)和掩饰(特定品的间隔)可能会对案文的总宽度产生重大影响。

另一个例子是,根据单一特性的宽度(W ,通常是拉丁字体最广的特性之一)和特定字体大小的高度度,得出粗略估计。 这种方法没有说明你文本中所有精细体的实际宽度,也没有考虑ker。

这里,你如何能够通过考虑每条精彩的宽度和酌情使用掩体来更准确地衡量案文。 这种方法计算了案文中每一特性的宽度,并加以补充,必要时对身高的舱面进行调节:

use rusttype::{Font, Scale, point, PositionedGlyph};

fn text_width(font: &Font, text: &str, scale: Scale) -> i32 {
    let mut total_width = 0;
    let v_metrics = font.v_metrics(scale);
    let height = (v_metrics.ascent - v_metrics.descent + v_metrics.line_gap).ceil() as i32;

    let glyphs: Vec<PositionedGlyph< _>> = font.layout(text, scale, point(0.0, 0.0)).collect();

    let mut last_glyph_id = None;
    for glyph in glyphs {
        if let Some(id) = last_glyph_id {
            if let Some(kern) = font.pair_kerning(scale, id, glyph.id()) {
                total_width += kern.ceil() as i32;
            }
        }

        if let Some(h_metrics) = glyph.h_metrics() {
            total_width += h_metrics.advance_width.ceil() as i32;
        }

        last_glyph_id = Some(glyph.id());
    }

    (total_width, height)
}

fn main() {
    let fs = 64.0;
    let font_data: &[u8] = include_bytes!("/usr/share/fonts/noto/NotoSans-Bold.ttf");
    let font = Font::try_from_bytes(font_data).expect("Error constructing Font");
    let scale = Scale::uniform(fs);
    let text = "Your text here";
    let (width, height) = text_width(&font, text, scale);

    println!("Width: {}, Height: {}", width, height);
}

这种做法如下:

  1. Iterates through each glyph that makes up the input text.
  2. Accounts for kerning adjustments between each pair of glyphs.
  3. Sums the width of each glyph, including kerning adjustments, to calculate the total width of the text.
  4. Calculates the height based on font metrics, which can be used as is from your original code.

这种方法更精确地衡量案文的尺寸,因为它考虑了案文中每一英寸的实际宽度,并调整了在精细之间加的宽度,导致比假设所有特性的宽度更精确的宽度。





相关问题
How to start to create an application GUI using C#?

HI! I am new to C# and plan to use it for my application GUI. I am trying to make my GUI similar to SPSS:http://www.spss.com/images/08/statistics_screens/ez_rfm-big.jpg Is this easy in C#? Is there ...

Automatic height of edit box

My shoes application has three items stacked on top of each other (with a stack, of course), in order: A banner An edit box Two buttons in a flow What I want to do is have the banner stay at it s ...

Search by using the keyboard in a list/grid - algorithm

I need to implement a custom search in a grid and I would like to find some user interface guidelines that explain the standard way to implement it. I mean this kind of search that is initiated by ...

UI And TcpClient Issue in vb.net

I m having some problems with a small ircbot i m writing. Basically I connect to the server using a tcpclient in a seperate class, which also runs on its own thread. I want to display the server text ...

UI Convention: Shortcut key for application exit? [closed]

Is there a convention for the shortcut keys for application exit? Some applications uses Alt+X some others use Ctrl+ X and Ctrl+Q. Applications like FF and IE doesnot assign a shortcut at all. So is ...

热门标签