Open incetarik opened 2 years ago
Any update?
You can probably get what you need with this:
TextStyle
for your textLayout::new
, and append the TextStyle
s to itlayout.glyphs()
. You can use the x, y, width, and height to figure out individual bounds for each letter; the min and max of each of those values should give you the 4 bounds of your bounding box.
Something like this:let mut layout = Layout::new(CoordinateSystem::PositiveYUp);
layout.append(
&[&self.font],
&TextStyle::new(string, self.font_size, 0),
);
for glyph in layout.glyphs() {
let left = glyph.x;
let top = glyph.y;
let right = glyph.x + glyph.width;
let bottom = glyph.y + glyph.height; // may need to flip the sign, or flip top and bottom depending on CoordinateSystem
// find the max of each of these, and that will be your bounding box.
}
@leecbaker Hi :wave: You're calculating each character's bounds, but I think the author wants the whole text bounds. I'm wrong, I'm just showing a hopefully more efficient version.
@incetarik I have the following code for calculating the whole text bounds:
// after making your text `Layout`:
let glyphs = layout.glyphs();
let text_width = match layout.lines() {
Some(lines) => lines
.iter()
.map(|ln| {
let glyph = &glyphs[ln.glyph_end];
glyph.x + glyph.width as f32
})
// same as `.max()`, but for the non-Ord `f32`
.fold(0.0 / 0.0, |m, v| v.max(m)),
None => 0.0,
};
let text_height = layout.height();
Window rendering with the calculated with/height (with no padding):
The width is measured correctly. The height might have to be adjusted if I make mistake. @leecbaker 's answer would be more accurate about the height. Combining the two might be the best answer.
You can probably get what you need with this:
- Assuming you already have a font
- Create one or more
TextStyle
for your text- Create a Layout with
Layout::new
, and append theTextStyle
s to it- Iterate through the glyphs in the layout with
layout.glyphs()
. You can use the x, y, width, and height to figure out individual bounds for each letter; the min and max of each of those values should give you the 4 bounds of your bounding box. Something like this:let mut layout = Layout::new(CoordinateSystem::PositiveYUp); layout.append( &[&self.font], &TextStyle::new(string, self.font_size, 0), ); for glyph in layout.glyphs() { let left = glyph.x; let top = glyph.y; let right = glyph.x + glyph.width; let bottom = glyph.y + glyph.height; // may need to flip the sign, or flip top and bottom depending on CoordinateSystem // find the max of each of these, and that will be your bounding box. }
@leecbaker Hello, I have done the following, yet the results are not matching:
let mut layout = fontdue::layout::Layout::new(fontdue::layout::CoordinateSystem::PositiveYUp);
let style = fontdue::layout::TextStyle::new(input, opts.font_size, 0);
layout.append(&[&font], &style);
let (width, height) = layout.glyphs()
.iter()
.map(|g| {
let left = g.x;
let top = g.y;
let right = left + g.width as f32;
let bottom = top + g.height as f32;
let height = bottom - top;
(right, height)
})
.fold((0.0f32, layout.height()), |l, r| (l.0.max(r.0), l.1.max(r.1)));
Here are the tests:
Caption | Value |
---|---|
Rust Result | W: 284, H: 38 |
Font Size | 32px |
Caption | Value |
---|---|
Rust Result | W: 67, H: 38 |
Font Size | 32px |
Caption | Value |
---|---|
Rust Result | W: 281, H: 32 |
Font Size | 27px |
The font being tested is: Raleway-Medium
The font file:
Sorry about that! Fontdue may add more padding than is typically required between some glyphs, so the results will not match output as seen in the browser, or another tool.
Sorry about that! Fontdue may add more padding than is typically required between some glyphs, so the results will not match output as seen in the browser, or another tool.
@mooman219 will there be any action for this then? Or maybe providing another function that does not add extra padding? At least, which method would be more accurate? I may also iterate through the letters and use font.metrics
and then utilizeadvance_width
for example.
The extra padding is because I don't expose fractional offsets, so fontdue
is making some quality judgments for you at font creation time. This was an opinion I baked in because people using fractional offsets had the following issues:
The goal was to give you decent glyphs out of the box. Right now you'll get whole pixel glyph alignment without overlap,
Fractional offsets are actually already supported internally, but will need some work to expose in a friendly way. Coincidentally someone else just asked for this so it's probably about time for me to figure out what's ergonomic for both the average user of this library and for someone that's willing to dig into the spicy parts of layout.
Any improvements on this?
Hi, first of all thank you for your work.
I tried this library to measure a string in a given font. To test, I also had my SVG editor open and I saw that the characters bounds are 100% correct. Yet, I could not find a way to calculate the overall text bounding box. I mean the box I have in the SVG editor for the text itself, not the characters.
Could you please add an example for calculating the expected string bounding box, if there is a way to calculate that properly?