razrfalcon / ttf-parser Goto Github PK
View Code? Open in Web Editor NEWA high-level, safe, zero-allocation TrueType font parser.
License: Apache License 2.0
A high-level, safe, zero-allocation TrueType font parser.
License: Apache License 2.0
I ran into this font which defines and uses glyphs in the CFF
and glyf
tables: https://github.com/emilk/egui/blob/master/egui/fonts/Comfortaa-Regular.ttf
My rasterizer needs to know the point winding before it can run outline_glyph
. For TrueType, a counter clockwise contour will always define the outside edge of a filled area, and a clockwise contour will always define the inside edge of a filled area. This is reversed for OpenType fonts.
Is there a way to know if for a given GlyphId
, the glyph is from an OpenType table or TrueType table?
https://github.com/yeslogic/allsorts seems to implement its own TTF parsing. It would be interesting to compare it with ttf-parser. Perhaps there are also code sharing opportunities.
When the CFF support is more complete, maybe rename the crate to make it easier to find?
in os2.rs#width()
, due to the default number in Rust is i32, here Stream::read_at
will read 4 bytes instead of the length of width (which is u16, 2 bytes), leading to width never correctly parsed
original issues is :
alexheretic/ab-glyph#10
These three tables are key to modern fonts, especially for non-latin scripts.
rustybuzz
already parses these tables to do glyph substitution and positioning, so the parsing code simply needs to be refactored for use in this library.
(If there's some reason keep the parsing of said tables in rustybuzz
, it should be documented in the README)
I have a regression test for #49 that's been broken by 0.12.2
.
For example for airstrip GlyphId(89)
.
Rect {
x_min: 0,
y_min: -3,
x_max: 1102,
y_max: 1301,
}
Rect {
x_min: 0,
y_min: 0,
x_max: 0,
y_max: 0,
}
During glyph layout (in glyph_brush_layout) I check if a glyph is invisible or not which can impact whether a word can fit into a line or not.
This check is currently done by see if the glyph has a bounding box or not, which is fast for the ttf fonts that are currently supported. Looking forward to using .otf this will no longer be a generally fast method.
Is there a quick way of checking this in general for .otf?
Another related idea is to switching the full compute OutlineBuilder
with an OutlineIterator
. If we had that presumably it would be possible to call:
let invisible = g.outline_iter().next().is_none()
Looks like they are rarely used, so no need to hurry. opentype.js
and fonttools
doesn't support them too.
Looks like they are rarely used, so no need to hurry. opentype.js
and fonttools
doesn't support them too.
According to the microsoft specification usWin*
should be used for getting the ascend/descend if the USE_TYPO_METRICS bit is not set.
I am specifically hitting this with some fonts from fontlab where the USE_TYPO_METRICS bit is not set and the hhea
table is practically empty.
Source for specification:
https://docs.microsoft.com/en-us/typography/opentype/spec/os2#stypoascender
I'm trying to render a text entry box that allows for up to 30 characters to be entered. To calculate its width, I need to know the max possible width of a 30-character string. Assuming nothing funny happens with spacing between letters, I think I can just multiply 30 by the max width of any character in that font.
I found global_bounding_box, and so I'm trying this:
let font_id = ...;
let font_size = 21;
fontdb.with_face_data(font_id, |data, face_index| {
let font = ttf_parser::Face::from_slice(data, face_index).unwrap();
let scale = (font_size as f64) / (font.units_per_em().unwrap() as f64);
scale * font.global_bounding_box().width() as f64
})
For the Overpass regular font, I get 30.4 from this, which seems visually to be too wide for most of the alphanumeric characters I'm trying out. Is there maybe an outlier character that's especially wide, or is this calculation incorrect? I'm not sure what units global_bounding_box
returns, nor if my understanding of units_per_em
is correct.
Thanks!
Hi!
I'm playing around with replacing FreeType with tff-parser in one of my projects.
I've made a couple of changes to be able to embolden and slant an outline.
The embolden algorithm is ported directly from the FreeType sources. To change
as little as possible of the original source I added a new method (that does nothing by default)
on the OutlineBuilder
trait. The rest of the functionality lives in it's own module.
You can check my commit in this branch if interested:
I have an implementation of this in https://github.com/JAicewizard/ttf-parser, I have not been able to test this for all formats but for the font's I've been able to test with it has worked.
Should I make a pull-request? The reading style of the getting a glyph id out of the cmap is something I am not used to and decided not to use for my own sake, I understand it makes it more difficult to accept.
The ttf_parser::kern::Subtable
API allows you to get the kerning information for two ordered glyphs.
Given stateful kerning (format 1) is unsupported, would it be reasonable to add API to iterate through all kerning pairs in a subtable? This is definitely trivial for format 0, but I haven't looked into 2 and 3.
Just posted a crate (https://crates.io/crates/ttf-utils) that uses this lib.
It contains functionality to apply fake bold and fake italic to a glyph outline.
The embolden algorithm is ported from the latest FreeType release.
cc @jrmuizel
I am getting
/usr/bin/ld: subprojects/ttf-parser/libttf_parser_capi.a(std-205127404fcba336.std.595pxchd-cgu.0.rcgu.o): undefined reference to symbol 'pthread_getattr_np@@GLIBC_2.2.5'
and
/usr/bin/ld: subprojects/ttf-parser/libttf_parser_capi.a(std-205127404fcba336.std.595pxchd-cgu.0.rcgu.o): in function 'std::sys::unix::weak::fetch': /rustc/49cae55760da0a43428eba73abcb659bb70cf2e4//src/libstd/sys/unix/weak.rs:61: undefined reference to 'dlsym'
if I don't pass thread_dep, cpp.find_library('dl')
(which currently I am) and guess those are coming from rust's std
, can c-api also become no_std so I can avoid passing https://github.com/harfbuzz/harfbuzz/pull/2510/files#diff-9356922ca3ded90602b144c3b5851dd2R8 pthread and libdl to it? Or is it something you are interested in at all so I can also have a look?
Thanks!
First of all I'm excited about this project especially it is wasm friendly! I'm wondering if we have API that can return the global bbox
like FreeType2 does: https://www.freetype.org/freetype2/docs/tutorial/step2.html, section 3 Global Metrics of bbox
.
You're ignoring the encoding ID but accepting a Unicode char
as the lookup. This is incorrect behavior. If the encoding is some windows code page instead, and you lookup the Unicode 'a', whatever you get back is worthless. If you do get a mapping for it, it's definitely not for the letter a.
It's likely that fonts that use non-unicode encodings are rare in the wild, but this library will silently do the wrong thing as it stands.
@RazrFalcon have you thought about font fallbacks? As I understand, there are two parts: selecting fallback fonts, and building a virtual font pulling glyphs from the first supporting font. The second part could be supported here or could be left to a higher-level library.
The Face
struct has several classes of methods:
from_slice
constructorhas_table
, table_data
, character_mapping_subtables
, ... — low-level stuff which it doesn't make sense to expose in a virtual "fallback font"is_regular
, is_monospaced
, weight
, ascender
, ... — properties which could be taken from the first font (or perhaps in some cases combined via a func like max
)glyph_index(char)
, glyph_hor_advance(glyph_id)
, outline_glyph(glyph_id, builder)
, ... — glyph-specific functionality abstracted over by the virtual fallback fontThe GlyphId
type currently uses a u16
which is likely insufficient for the fallback font — this type could be made an associated type of a trait or simply larger.
Given the above, it might make more sense to implement font fallback at a higher level, e.g. via the ab_glyph::Font
trait (if @alexheretic wishes to support font fallbacks), but I thought it would make sense to ask here first since (a) you (@RazrFalcon) may have already considered this and (b) whatever choice is made here has implications for downstream libraries (e.g. whether GlyphId
becomes an associated type).
Hi, I am working on porting ttf-parser
's CharString porting code to Allsorts. I noticed that in the CharString tests CFF fonts are built with an OffSize
in the header of zero, which Allsorts rejects. This works in ttf-parser
because this value is skipped. The comment on that line (and in the tests) suggest that perhaps is value has been misinterpreted as it's not an absolute offset but the size in bytes of absolute offsets with valid values being 1–4.
This is what the CFF1 reference says:
CFF2 says:
Name | Range | Description |
---|---|---|
OffSize | 1 to 4 | 1-byte unsigned number specifies the size of an Offset field or fields |
Anyway not a huge issue since the value is unused but I thought I'd mention it anyway.
It would be interesting to have a replacement for https://github.com/khaledhosny/ots that was written in Rust. To do that we'd need the ability to write out a parsed font.
I've been wondering why 'i' does not get rendered with this font (most glyphs do render). Is this hitting an unsupported feature?
Code: https://gist.github.com/dhardy/60ef7de0e291e54ef7b4e2f8b95e1819
Font: /usr/share/fonts/google-carlito-fonts/Carlito-Regular.ttf
Output:
ttf-parser index: 98
ttf-parser bounding box: Rect { x_min: 110, y_min: 0, x_max: 357, y_max: 1409 }
ttf-parser failed to outline glyph
fontdue index: 98
fontdue metrics: Metrics { xmin: 0, ymin: 0, width: 0, height: 0, advance_width: 9.1796875, advance_height: 0.0, bounds: OutlineBounds { xmin: 0.0, ymin: 0.0, width: 0.0, height: 0.0 } }
https://github.com/RazrFalcon/ttf-parser/blob/master/src/lib.rs#L580
pub struct Face<'a> {
...
}
impl<'a> Face<'a> {
pub fn from_slice(data: &'a [u8], index: u32) -> Result<Self, FaceParsingError> {
}
}
It seems Face need reference the bytes for a long time.
I can not understand of the lifetime here, why it is necessity?
Is font parse not one-time action?
For this reason, I can't simply define a struct attr like:
pub struct Renderer {
font: Face, // <---- error!!! must gave a lifetime
}
This puts a lot of restrictions on the code design.
But i really can't figure it out.
According to the spec:
The use of this format is discouraged.
So no need to hurry.
refactoring
This should speed up glyf
+gvar
bbox calculation.
Something equivalent to hb_font_get_glyph_extents
from ttf-parser would be nice so I can use in benchmarking, there is ttfp_get_glyph_{hor,ver}_{advance,side_bearing}
which I guess won't be good enough for comparison to that API.
Looks like they are rarely used, so no need to hurry. opentype.js
and fonttools
doesn't support them too.
Hello,
A recent of upgrade of the ttf-parser dependency in the femtovg crate has caused an issue with alignment of the icons (provided by characters in the entypo font), as can be seen here: femtovg/femtovg#56.
As noted in the issue, this problem has been tracked down to d32a5de, which added windows acender/ descender if the USE_TYPO_METRICS flag is not set.
Looking into this I think the problem may be in the is_use_typo_metrics()
function here:
Lines 268 to 274 in 9ab844b
This function returns false is the OS/2 table version is less than 4, which makes sense because the USE_TYPO_METRICS flag was only introduced in version 4, but this means that the above function will cause the selection of ascender/descender to default to windows. The entypo font has an OS/2 table which is version 3. Now I can't find anything in the docs to suggest what the default ascender/descender selection should be for fonts with a version less than 4, but since it seems to be broken I would guess that maybe it should default to typographic.
My knowledge of font tables is limited so let me know if I'm way off here and if the solution should be on the femtovg usage side of things. Thanks.
Line 312 in 9a10cdb
You know, y_min <= y_min
is always true
...
This font has glyph(s) that produce return invalid bounding boxes, e.g. with y_min == y_max
. I'd expect these to return None
when calling outline_glyph
.
Presumably this font is dodgy. Should ttf-parser handle this or should I downstream?
// [dependencies]
// ttf-parser = "0.12"
/// https://github.com/gearit/ttf-symbola/raw/master/Symbola.ttf
const FONT: &[u8] = include_bytes!("../Symbola.ttf");
fn main() {
let face = ttf_parser::Face::from_slice(FONT, 0).unwrap();
let gid = ttf_parser::GlyphId(893);
let bounds = face.outline_glyph(gid, &mut OutlinePrinter);
eprintln!("outline_glyph({:?}, _) = {:?}", gid, bounds);
if let Some(b) = bounds {
assert!(b.x_min < b.x_max && b.y_min < b.y_max);
}
}
struct OutlinePrinter;
impl ttf_parser::OutlineBuilder for OutlinePrinter {
fn move_to(&mut self, x: f32, y: f32) {
eprintln!("outline-move_to({}, {})", x, y);
}
fn line_to(&mut self, x: f32, y: f32) {
eprintln!("outline-line_to({}, {})", x, y);
}
fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
eprintln!("outline-quad_to({}, {}, {}, {})", x1, y1, x, y);
}
fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
eprintln!(
"outline-curve_to({}, {}, {}, {}, {}, {})",
x1, y1, x2, y2, x, y
);
}
fn close(&mut self) {
eprintln!("outline-close");
}
}
outline-move_to(0, 1606)
outline-line_to(0, 1606)
outline-close
outline-move_to(2048, 1606)
outline-line_to(2048, 1606)
outline-close
outline_glyph(GlyphId(893), _) = Some(Rect { x_min: 0, y_min: 1606, x_max: 2048, y_max: 1606 })
thread 'main' panicked at 'assertion failed: b.x_min < b.x_max && b.y_min < b.y_max', src/main.rs:14:9
ab-glyph issue: alexheretic/ab-glyph#32
Using airstrip.ttf https://dl.dafont.com/dl/?f=airstrip_four character v
returns a zero bounding box result from outline_glyph
which seems wrong.
const AIRSTRIP: &[u8] = include_bytes!("../airstrip.ttf");
fn main() {
let airstrip = ttf_parser::Face::from_slice(AIRSTRIP, 0).unwrap();
let v = airstrip.glyph_index('v').unwrap();
let bounds = airstrip.outline_glyph(v, &mut OutlinePrinter);
dbg!(bounds);
}
struct OutlinePrinter;
impl ttf_parser::OutlineBuilder for OutlinePrinter {
fn move_to(&mut self, x: f32, y: f32) {
eprintln!("outline-move_to({}, {})", x, y);
}
fn line_to(&mut self, x: f32, y: f32) {
eprintln!("outline-line_to({}, {})", x, y);
}
fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
eprintln!("outline-quad_to({}, {}, {}, {})", x1, y1, x, y);
}
fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
eprintln!("outline-curve_to({}, {}, {}, {}, {}, {})", x1, y1, x2, y2, x, y);
}
fn close(&mut self) {
eprintln!("outline-close");
}
}
outline-move_to(955, 1301)
outline-quad_to(864, 1298, 833, 1247)
outline-quad_to(802, 1196, 552, 447)
outline-quad_to(300, 1196, 272.5, 1248.5)
outline-quad_to(245, 1301, 150, 1301)
outline-quad_to(0, 1301, 0, 1151)
outline-line_to(401, 99)
outline-quad_to(443, 14, 493.5, 5.5)
outline-quad_to(544, -3, 602.5, 2.5)
outline-quad_to(661, 8, 697, 99)
outline-line_to(1102, 1149)
outline-quad_to(1102, 1301, 955, 1301)
outline-close
[src/main.rs:11] bounds = Some(
Rect {
x_min: 0,
y_min: 0,
x_max: 0,
y_max: 0,
},
)
COLR format fonts are part of the OpenType specification. It is the perfect companion for emoji and font icons in usage scenarios. This has become so popular that all major browsers support COLRv0.
And Chrome will soon ship COLRv1, which will bring many new features such as gradients, transforms and compositing.
2023-09-21
Font: https://github.com/arrowtype/recursive/releases/download/v1.070/ArrowType-Recursive-1.070.zip Recursive_VF_1.070.ttf
font2svg example has many missing glyphs.
Is this font format not supported yet?
Like in Font::glyph_bounding_box
.
https://rust-lang.github.io/rustfmt/
I started writing a PR to add iterators for the 3 supported Kerning tables, but trashed the file formatting on save to my defaults. Do you mind adding a rustfmt.toml
to your root with the styling you prefer?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.