Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Potential Way get length of text at certain fontsize #49

Open
Charles-Schleich opened this issue May 12, 2020 · 11 comments
Open

Potential Way get length of text at certain fontsize #49

Charles-Schleich opened this issue May 12, 2020 · 11 comments
Milestone

Comments

@Charles-Schleich
Copy link

Charles-Schleich commented May 12, 2020

I have been wondering if it would be possible to get the length of a line of text for a certain font and at a certain font size.
Something along the lines of

get_length( text: String, font_size: i64 , font: &IndirectFontRef) -> Mm;

Any idea how I might go about implementing something like this ?
Or where I should start ?
I'm newish to rust, but I'm keen to give it a shot.

@fschutt
Copy link
Owner

fschutt commented May 12, 2020

Wrong crate, this is a PDF library. I've written azul_text_layout for this: https://crates.io/crates/azul-text-layout

See here:

use azul_text_layout::{
    text_layout::{split_text_into_words, words_to_scaled_words},
    text_shaping::get_font_metrics_freetype, 
};

let font = include_bytes!("Helvetica.ttf");
let font_index = 0; // only for fonts with font collections
let font_metrics = get_font_metrics_freetype(&font, font_index);
let words = split_text_into_words("hello");
let scaled_words = words_to_scaled_words(&words, font, font_index, font_metrics, font_size);

let total_width = scaled_words.items.iter().map(|i| i.word_width).sum();

@fschutt
Copy link
Owner

fschutt commented May 12, 2020

Note: this doesn't take into account the width of the spaces between the words.

If you want to do a full text layout (including more advanced things like line breaking, line offset, custom character / word spacing) azul-text-layout does support that too, see here: #39 (comment)

@Charles-Schleich
Copy link
Author

Charles-Schleich commented May 14, 2020

Fantastic stuff, if want to account for the width of spaces as well It looks like I can also use scaled_words.space_advance_px,

These are some great libraries.
Thank you for pointing me in the right direction !

@Charles-Schleich
Copy link
Author

Potentially related, is there a way to set the local origin on a line of text to be the top left, as opposed to bottom left ? (i.e. such that the text draws downwards from the origin)
Alternatively, I've been trying to offset the y coordinate on the .use_text(text, fontsize, x, y, &font); method by the height of the font in the following manner:

let font_metrics = get_font_metrics_freetype(font, font_index as i32);
let font_height = font_metrics.get_height(fontsize);

Unfortunately this font_height does not correspond nicely to the Mm() scale expected by .use_text(), and even after tinkering to scale the value used to offset, I haven't managed to find a good way to do this that is consistent for many different fonts.

@maku
Copy link

maku commented Nov 16, 2020

@fschutt You wrote printpdf is the wrong crate. I am curious how would you implement something where you have to "right align" numeric values and so on. From my naive point of view I would see the need to calculate the width of a text with specific parameters (font etc.). Is this a use case where printpdf is not the right tool for the job?

@fschutt
Copy link
Owner

fschutt commented Nov 16, 2020

@maku

Is this a use case where printpdf is not the right tool for the job?

Yes. printpdf does not do text layout. I've written another crate azul-text-layout with which you can use to calculate the per-line offset. PDF does not know what "right align" means, it only knows left-align. So you have to calculate an "offset" for each line of text that you want to right-align.

Text layout / text shaping is more complicated that most people realize. Which is why it's the job of a text layout library, not a PDF library.

@maku
Copy link

maku commented Nov 17, 2020

@fschutt thanks for answering, but I still don't understand correctly, azul-text-layout is not a PDF document creation lib, right? What would be the way when I have to generate a PDF with Rust that should display numbers right-aligned? You mean use azul-text-layout only for calculation purposes and printpdf for the rest?. Somehow this has to be possible since it is also possible in libraries in other programming languages. Even if it might be complicated ... can you give me some advice?

@fschutt
Copy link
Owner

fschutt commented Nov 17, 2020

You mean use azul-text-layout only for calculation purposes and printpdf for the rest?

Yes. There is some code here to get you started: #39 (comment) and on the docs.rs page

Essentially you'll want to set horizontal_alignment = StyleTextAlignmentHorz::Right and set text_layout_options.max_horizontal_width = None. Then just copy the rest of the code - the "right aligning" is done by calling set_text_cursor, which places the text relative to the page. So if you want to right align a text block of numbers, all you'll have to do is to add the coordinate of the line to the coordinate of the text block.

@ninjacato
Copy link
Contributor

For anyone else stumbling upon this, I went for an alternative route and used rusttype and extracted this function from genpdf-rs to do the text measurements

 pub fn str_width(&self, font_cache: &FontCache, s: &str, font_size: u8) -> Mm {
        let str_width: Mm = font_cache
            .get_rt_font(*self)
            .glyphs_for(s.chars())
            .map(|g| g.scaled(self.scale).h_metrics().advance_width)
            .map(|w| Mm::from(printpdf::Pt(f64::from(w * f32::from(font_size)))))
            .sum();
        let kerning_width: Mm = self
            .kerning(font_cache, s.chars())
            .into_iter()
            .map(|val| val * f32::from(font_size))
            .map(|val| Mm::from(printpdf::Pt(f64::from(val))))
            .sum();
        str_width + kerning_width
    }

And converted the width of the text to MM in 72dpi like (str_width + kerning_width) * (25.4 / 72.0)

@fschutt
Copy link
Owner

fschutt commented Apr 27, 2022

@ninjacato You just have to be aware that rusttype has very rudimentary font shaping and no WOFF2 file support (while azul-text-layout uses the allsorts font shaping engine and does have these features).

@fschutt
Copy link
Owner

fschutt commented Nov 2, 2024

printpdf 0.8 will now have a rudimentary layout system using HTML, so this issue should be solved by then.

@fschutt fschutt added this to the 0.8 milestone Nov 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants