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

Getting the number of faces #126

Closed
nyurik opened this issue Jul 9, 2023 · 15 comments
Closed

Getting the number of faces #126

nyurik opened this issue Jul 9, 2023 · 15 comments

Comments

@nyurik
Copy link

nyurik commented Jul 9, 2023

It seems there is currently no way to find out how many faces a font file has. The relevant code reads it internally, but I do not see any way to access this info. In freetype-rs, there is a method to get the face count after the index-0 face has been loaded. While not ideal, it seems like this is an OK solution here as well? Also, perhaps there could be a way to not re-parse the metadata, but instead have a way to iterate over all faces, yielding one face at a time?

https://github.com/RazrFalcon/ttf-parser/blob/ba2d9c8b9a207951b7b07e9481bc74688762bd21/src/lib.rs#L666-L671

@notgull
Copy link

notgull commented Jul 9, 2023

@nyurik
Copy link
Author

nyurik commented Jul 9, 2023

Thanks! I'm afk, but seems like that's what I have been missing, will submit a small docs clarification soon. Do you know how efficient is the iteration over all faces? Does it cause a re-parse, or worse, require a clone of the original data on each face retrieval?

@notgull
Copy link

notgull commented Jul 9, 2023

It just reads the first few bytes of the face to determine if it's a font collection and then how many fonts are in it. It's as cheap as cheap can be.

@nyurik
Copy link
Author

nyurik commented Jul 9, 2023

@notgull sadly, it seems the story is a bit more complex. You are absolutely correct that fonts_in_collection is very fast returns the face count. The issue is that it seems that owned_ttf_parser which extends ttf_parser consumes Vec<u8> data, while only allowing to read just one index. Both crates had commits by @RazrFalcon, so perhaps they know if its possible to get multiple faces without re-reading/cloning source data?

@notgull
Copy link

notgull commented Jul 9, 2023

Forgive me if I'm misunderstanding, but if you've already passed the font data into an OwnedFace, can't you just use as_slice to get the underlying data for this method?

I feel like this is an XY problem. Do you have more information on what you're trying to do?

@RazrFalcon
Copy link
Collaborator

RazrFalcon commented Jul 10, 2023

@nyurik I have no relation to owned_ttf_parser. You should ask the author of that crate.

I'm not sure what you're trying to do, but just in case you have to understand that faces in a font collection are not independent. They can reference the same TrueType tables. That's the whole point.
And yes, ttf-parser would parse those tables each time. It's a zero-allocation library after all.

@nyurik
Copy link
Author

nyurik commented Jul 10, 2023

@notgull and @RazrFalcon thank you so much for a quick reply!

I am the maintainer of Martin tile server (maps), and trying to add dynamic font generation support using sdf_font_tools crates.

Users of Martin will ask for one or more fonts, e.g. HTTP .../font/Metropolis Regular,Noto Sans Regular/0-255 -- which means get glyphs in the 0-255 codepoint range, where each glyph would be from either Metropolis Regular or Noto Sans Regular, whichever font has it first. The glyphs are rendered in a SDF format (sign distance field images).

During startup, I need to iterate over all available fonts and their faces, discover available glyph codepoints and store them as bit-sets. On request, I will iterate over the combined bitset for the requested codepoint range, generate needed SDF images for glyphs and send them to the client. Eventually I may pre-cache SDF images at a significantly higher memory requirements.

Currently, sdf_font_tools uses freetype-rs bindings, and I don't even have a way to iterate over available glyphs - instead I brute-force it with for i in 0..65536 { get_char_index(i) }.

I would like to switch to a Rust-based font parsing/rendering stack, and hence the rusttype lib which uses ttf-parser.

@notgull
Copy link

notgull commented Jul 10, 2023

You may want to look into fontdb, as it already handles most of the font discovery/font enumeration use cases out of the box.

@RazrFalcon
Copy link
Collaborator

I don't think you need owned_ttf_parser to begin with. You're suppose to "create" ttf_parser::Face on each access. And it's designed to be very cheap.

The typical ttf_parser usage is:

  1. memory-map a font file
  2. parse Face
  3. collect necessary info from the face
  4. profit

You should not keep ttf_parser::Face around. It's pointless.

@nyurik
Copy link
Author

nyurik commented Jul 10, 2023

@RazrFalcon do you know why rusttype uses owned_ttf_parser? I presumed it is the Rust re-implementation of the freetype-rs.

Here's the code that actually calls freetype face rendering functions - is this something i can do directly from ttf-parser, or do i need a separate lib for that?

https://github.com/stadiamaps/sdf_font_tools/blob/dc2042534617576eadf14f15381bf3ffe1d0c3f2/sdf_glyph_renderer/src/ft.rs#L47

  • face.set_char_size(0, (size << 6) as isize, 0, 0)
  • face.size_metrics
  • face.get_char_index
  • face.load_glyph(glyph_index, LoadFlag::NO_HINTING | LoadFlag::RENDER)
  • face.glyph
  • glyph.bitmap

@RazrFalcon
Copy link
Collaborator

do you know why rusttype uses owned_ttf_parser?

Maybe they find it easier. Idk.

The only thing missing from ttf_parser here is "font size". It operates on font units, meaning you have to downscale glyph outlines and bitmaps yourself.
And ttf_parser, as the name suggests, doesn't renderer anything.

PS: I think you're optimizing for a non-existing case.

@notgull
Copy link

notgull commented Jul 10, 2023

If memory serves rusttype is only passively maintained and generally isn't used anymore. I've had good results with swash and ab-glyph as glyph rasterizers.

@nyurik
Copy link
Author

nyurik commented Jul 11, 2023

Thanks, I wasn't aware rusttype was semi-dead. Both swash and ab-glyph look promising - any recommendation of choosing one over the other for my use case? Thank you for all the feedback!

@notgull
Copy link

notgull commented Jul 11, 2023

If I recall correctly, swash has better emoji handling capabilities, if that's important to you.

@RazrFalcon
Copy link
Collaborator

ab-glyph is a renderer. swash is a renderer + shaper (aka a layout).

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

3 participants