mooman219 / fontdue Goto Github PK
View Code? Open in Web Editor NEWThe fastest font renderer in the world, written in pure rust.
License: Apache License 2.0
The fastest font renderer in the world, written in pure rust.
License: Apache License 2.0
I have in-engine text rendering working. For now I hardcode scale == 40.0. I noticed when I render font size at 40px it looks great, but this other text at 15px has the appearance of character spacing/alignment being off by a pixel.
Thanks for the great library!
My fuzzer found a segfault when rendering the character 'g'
, scale 60.0
, with the attached font:
segfault.zip
Just wondering what the state / milestones are around subpixel positioning? I see rasterize_subpixel()
got added recently, but that appears to quantize to units of 1/3 of a pixel.
Iced would love to switch to using fontdue, but subpixel positioning is a need for our layouts.
Text seems to be top aligned, or not even aligned at all when iterating over the &GlyphPosition
s and rasterizing them with rasterize_config
.
Sample code:
let mut img3 = ImageBuffer::<Pixel, _>::new(WIDTH, HEIGHT);
// Fontdue
{
let canvas = &mut img3;
let mut layout = Layout::new();
let mut output = Vec::new();
let helvetica = Font::from_bytes(HELVETICA_DATA, FontSettings::default()).unwrap();
let fonts = &[helvetica];
let (x, y) = (100, 200);
let color = Pixel::from([Depth::MAX, Depth::MAX / 4, Depth::MAX / 2, Depth::MAX]);
layout.layout_horizontal(
fonts,
&[
&TextStyle::new("Hello ", 35.0, 0),
&TextStyle::new("world!", 50.0, 0),
],
&LayoutSettings {
// max_width: Some(150.0),
x: x as f32,
y: y as f32,
max_height: Some(10.0),
..LayoutSettings::default()
},
&mut output,
);
output.iter().for_each(|c| {
let (metrics, pixels) = fonts[c.key.font_index].rasterize_config(c.key);
dbg!(&c);
draw_filled_rect_mut(
canvas,
Rect::at(c.x as _, c.y as i32 + c.height as i32)
.of_size(c.width as _, c.height as _),
Rgba([0, !0, 0, !0]),
);
pixels.into_iter().enumerate().for_each(|(i, p)| {
let p = (p as f32 / u8::MAX as f32);
let image_x = (c.x as i32 + (i % c.width) as i32);
let image_y = ((c.y as i32 + (c.height as i32)) + (i / c.width) as i32);
let image_width = canvas.width() as i32;
let image_height = canvas.height() as i32;
if image_x >= 0 && image_x < image_width && image_y >= 0 && image_y < image_height {
let pixel = *canvas.get_pixel(image_x as u32, image_y as u32);
let weighted_color = weighted_sum(pixel, color, 1.0 - p, p);
canvas.draw_pixel(image_x as u32, image_y as u32, weighted_color);
}
});
});
}
My fuzzer found a stack overflow while attempting to parse the included font file.
Did some fuzzing of the function fontdue::Font::from_bytes
and found this crash:
$ RUST_BACKTRACE=1 ./target/debug/fontdue-crash
thread 'main' panicked at 'attempt to add with overflow', /home/capitol/.cargo/git/checkouts/fontdue-8bd74c91401c4cc7/dc8670e/src/font.rs:113:28
stack backtrace:
0: rust_begin_unwind
at /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/std/src/panicking.rs:475
1: core::panicking::panic_fmt
at /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/core/src/panicking.rs:85
2: core::panicking::panic
at /rustc/397b390cc76ba1d98f80b2a24a371f708dcc9169/library/core/src/panicking.rs:50
3: fontdue::font::LineMetrics::new
at /home/capitol/.cargo/git/checkouts/fontdue-8bd74c91401c4cc7/dc8670e/src/font.rs:113
4: fontdue::font::Font::from_bytes
at /home/capitol/.cargo/git/checkouts/fontdue-8bd74c91401c4cc7/dc8670e/src/font.rs:280
5: fontdue_crash::main
at ./src/main.rs:5
6: core::ops::function::FnOnce::call_once
at /home/capitol/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227
Can be reproduced with this program:
fn main() {
let font = vec![0, 1, 0, 0, 0, 250, 255, 255, 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 101, 210, 210, 58, 117, 210, 32, 0, 109, 97, 112, 126, 33, 0, 0, 0, 0, 0, 99, 102, 1, 0, 30, 1, 91, 1, 0, 253, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 0, 86, 79, 82, 71, 0, 1, 82, 77, 103, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 35, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 0, 30, 1, 91, 1, 0, 253, 0, 86, 79, 82, 71, 0, 1, 82, 77, 103, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 1, 77, 103, 118, 97, 114, 220, 255, 255, 255, 255, 255, 255, 0, 236, 0, 0, 98, 77, 1, 91, 0, 0, 220, 70, 70, 50, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 97, 114, 120, 0, 0, 0, 0, 30, 1, 91, 1, 0, 253, 0, 86, 79, 82, 71, 0, 1, 82, 77, 103, 118, 97, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 82, 71, 0, 0, 0, 0, 0, 118, 97, 0, 1, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 250, 184, 102, 118, 97, 114, 115, 98, 105, 120, 0, 0, 0, 0, 0, 0, 0, 4, 61, 6, 82, 77, 220, 45, 103, 79, 41, 114, 117, 250, 184, 102, 118, 97, 114, 115, 98, 105, 120, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 64, 255, 0, 0, 116, 116, 99, 102, 33, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 8, 17, 0, 0, 0, 6, 0, 72, 0, 0, 0, 1, 0, 0, 210, 5, 0, 0, 0, 0, 0, 0, 0, 255, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 0, 109, 97, 98, 105, 120, 0, 0, 0, 0, 0, 0, 0, 4, 61, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 117, 210, 0, 0, 33, 93, 112, 126, 33, 0, 0, 0, 0, 103, 118, 97, 114, 220, 70, 70, 55, 0, 0, 0, 0, 0, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 0, 0, 0, 109, 97, 112, 126, 33, 0, 0, 0, 0, 0, 99, 102, 1, 0, 30, 1, 91, 1, 0, 253, 0, 210, 58, 117, 210, 0, 0, 109, 97, 112, 126, 33, 0, 0, 255, 0, 0, 0, 99, 102, 1, 0, 30, 1, 91, 1, 0, 253, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 255, 101, 210, 210, 58, 117, 210, 32, 0, 255, 255, 255, 109, 255, 255, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 253, 0, 109, 97, 120, 112, 0, 1, 0, 253, 0, 0, 0, 0, 0, 0, 0, 64, 255, 70, 51, 0, 0, 0, 0, 0, 0, 0, 116, 116, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 97, 120, 112, 0, 1, 0, 58, 117, 0, 0, 205, 0, 0, 1, 0, 0, 253, 0, 0, 0, 0, 0, 0, 0, 64, 255, 255, 210, 1, 255, 255, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 17, 17, 17, 0, 67, 70, 70, 50, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 27, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 3, 72, 0, 0, 0, 0, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 1, 77, 103, 118, 97, 114, 220, 255, 255, 255, 255, 255, 255, 0, 236, 0, 0, 98, 77, 103, 118, 97, 77, 65, 0, 0, 1, 0, 0, 0, 1, 174, 178, 35, 0, 45, 79, 104, 104, 101, 97, 169, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 36, 120, 169, 0, 1, 0, 0, 0, 0, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 101, 210, 210, 58, 117, 0, 1, 0, 0, 0, 27, 0, 1, 0, 0, 1, 0, 255, 255, 255, 255, 148, 0, 0, 0, 0, 0, 118, 97, 1, 1, 0, 0, 4, 61, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 101, 210, 210, 58, 117, 210, 32, 0, 109, 97, 112, 126, 33, 0, 0, 0, 0, 16, 99, 0, 1, 30, 1, 102, 91, 1, 0, 253, 0, 86, 79, 210, 71, 0, 1, 103, 77, 82, 118, 97, 114, 220, 70, 70, 56, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 27, 0, 2, 251, 0, 1, 0, 255, 255, 255, 4, 148, 0, 0, 0, 0, 0, 97, 118, 0, 0, 1, 16, 0, 1, 82, 77, 0, 190, 250, 184, 105, 118, 97, 114, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 17, 0, 5, 64, 8, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 67, 70, 0, 0, 27, 0, 2, 251, 0, 1, 0, 255, 255, 255, 4, 148, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 1, 0, 0, 0, 242, 72, 77, 65, 82, 77, 0, 190, 255, 255, 255, 4, 148, 0, 0, 0, 0, 0, 97, 118, 0, 0, 250, 184, 102, 118, 97, 114, 115, 184, 98, 255, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 67, 70, 70, 49, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 1, 6, 0, 67, 70, 70, 0, 0, 118, 97, 114, 0, 116, 116, 99, 102, 33, 1, 0, 1, 0, 0, 0, 27, 0, 0, 0, 0, 0, 3, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 17, 0, 5, 64, 8, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 0, 0, 0, 67, 70, 70, 0, 0, 116, 116, 118, 97, 1, 148, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 1, 0, 0, 0, 242, 72, 77, 65, 82, 77, 0, 190, 250, 184, 102, 118, 97, 114, 115, 184, 98, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 67, 70, 70, 49, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 1, 6, 0, 67, 70, 70, 0, 0, 118, 97, 114, 0, 116, 116, 99, 102, 33, 1, 0, 1, 0, 0, 0, 27, 0, 0, 0, 0, 0, 3, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 17, 0, 5, 64, 8, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 0, 0, 0, 67, 70, 70, 0, 0, 116, 116, 118, 97, 1, 0, 0, 0, 1, 209, 77, 0, 190, 0, 1, 0, 0, 0, 1, 0, 0, 220, 104, 101, 97, 100, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 54, 110, 137, 0, 1, 12, 255, 255, 255, 255, 255, 255, 199, 107, 101, 114, 58, 27, 0, 1, 0, 0, 67, 70, 70, 0, 0, 255, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 255, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 97, 114, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 193, 17, 0, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 70, 0, 0, 116, 116, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 1, 28, 28, 114, 220, 70, 70, 51, 0, 0, 0, 0, 35, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 0, 30, 1, 91, 1, 0, 253, 0, 86, 79, 82, 71, 0, 1, 82, 77, 103, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 1, 77, 103, 118, 97, 114, 220, 255, 255, 255, 255, 255, 255, 0, 236, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 27, 0, 1, 255, 71, 86, 255, 255, 255, 148, 0, 0, 1, 0, 0, 1, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 103, 72, 77, 65, 0, 0, 1, 0, 0, 0, 1, 174, 178, 35, 0, 45, 79, 104, 104, 101, 97, 169, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 36, 120, 169, 0, 1, 0, 0, 0, 0, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 101, 210, 210, 58, 117, 0, 1, 0, 0, 0, 27, 0, 1, 0, 0, 1, 0, 255, 255, 255, 255, 148, 0, 0, 0, 0, 0, 118, 97, 1, 1, 0, 0, 4, 61, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 101, 210, 210, 58, 117, 210, 32, 0, 109, 97, 112, 126, 33, 0, 0, 0, 0, 16, 99, 0, 1, 30, 1, 102, 91, 1, 0, 253, 0, 86, 79, 210, 71, 0, 1, 103, 77, 82, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 27, 0, 2, 251, 0, 1, 0, 255, 255, 255, 4, 148, 0, 0, 0, 0, 0, 97, 118, 0, 0, 1, 16, 0, 1, 82, 77, 0, 190, 250, 184, 105, 118, 97, 114, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 17, 0, 5, 64, 8, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 67, 70, 0, 0, 27, 0, 2, 251, 0, 1, 0, 255, 255, 255, 4, 148, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 1, 0, 0, 0, 242, 72, 77, 65, 82, 77, 0, 190, 250, 184, 102, 118, 97, 114, 115, 184, 98, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 67, 70, 70, 50, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 1, 6, 0, 67, 70, 70, 0, 0, 118, 97, 114, 0, 116, 116, 99, 102, 33, 1, 0, 1, 0, 0, 0, 27, 0, 0, 0, 0, 0, 3, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 17, 0, 5, 64, 8, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 0, 0, 0, 67, 70, 70, 0, 0, 116, 116, 118, 97, 1, 0, 0, 0, 1, 209, 77, 0, 190, 0, 1, 0, 0, 0, 1, 0, 0, 220, 104, 101, 97, 100, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 54, 110, 137, 0, 1, 12, 255, 255, 255, 255, 255, 255, 199, 107, 101, 114, 58, 27, 0, 1, 0, 0, 67, 70, 70, 0, 0, 255, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 255, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 97, 114, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 193, 17, 0, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 70, 0, 0, 116, 116, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 1, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 5, 64, 24, 12, 12, 12, 12, 12, 12, 12, 99, 102, 1, 0, 30, 1, 91, 1, 0, 253, 0, 86, 79, 82, 71, 0, 1, 82, 0, 0, 30, 1, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 205, 0, 0, 1, 0, 0, 0, 0, 1, 209, 77, 0, 190, 0, 1, 0, 0, 0, 1, 0, 0, 220, 104, 101, 97, 100, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 54, 110, 137, 0, 1, 12, 255, 255, 255, 255, 255, 255, 199, 107, 101, 114, 58, 27, 0, 1, 0, 0, 67, 70, 70, 0, 0, 255, 15, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0, 0, 1, 0, 0, 1, 0, 255, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 97, 114, 115, 98, 105, 136, 0, 255, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 70, 0, 0, 116, 116, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 1, 28, 28, 114, 220, 70, 70, 51, 0, 0, 0, 0, 35, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 0, 30, 1, 91, 1, 0, 253, 0, 86, 79, 82, 71, 0, 1, 82, 77, 103, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 1, 77, 103, 118, 97, 114, 220, 255, 255, 255, 255, 255, 255, 0, 236, 0, 0, 116, 116, 99, 102, 33, 1, 125, 0, 0, 103, 118, 97, 114, 120, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 27, 0, 1, 255, 71, 86, 255, 255, 255, 148, 255, 65, 0, 0, 0, 0, 0, 118, 97, 1, 1, 0, 0, 4, 61, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 103, 72, 77, 65, 0, 0, 1, 0, 0, 0, 1, 174, 178, 35, 0, 45, 79, 104, 104, 101, 97, 169, 1, 0, 15, 0, 0, 0, 0, 0, 0, 0, 36, 120, 169, 0, 1, 0, 0, 0, 0, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 101, 210, 210, 58, 117, 0, 1, 0, 0, 0, 27, 0, 1, 0, 0, 1, 0, 255, 255, 255, 255, 148, 0, 0, 0, 0, 0, 118, 97, 1, 1, 0, 0, 4, 61, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 0, 1, 99, 109, 97, 112, 126, 33, 0, 0, 0, 0, 8, 0, 0, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 101, 210, 210, 58, 117, 210, 32, 0, 109, 97, 112, 126, 33, 0, 0, 0, 0, 16, 99, 0, 1, 30, 1, 102, 91, 1, 0, 253, 0, 86, 79, 210, 71, 0, 1, 103, 77, 82, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 27, 0, 2, 251, 0, 1, 0, 255, 255, 255, 4, 148, 0, 0, 0, 0, 0, 97, 118, 0, 0, 1, 16, 0, 1, 82, 0, 17, 0, 5, 64, 8, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 70, 0, 0, 27, 0, 2, 251, 0, 1, 0, 255, 255, 255, 4, 148, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 1, 0, 0, 0, 242, 72, 77, 65, 82, 77, 0, 190, 250, 184, 102, 118, 97, 114, 115, 184, 98, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 67, 70, 70, 50, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 1, 6, 0, 67, 70, 70, 0, 0, 118, 97, 114, 0, 116, 116, 99, 102, 33, 1, 0, 1, 0, 0, 0, 27, 0, 0, 0, 0, 0, 3, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 0, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 17, 0, 5, 64, 8, 38, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 77, 0, 190, 58, 27, 0, 0, 0, 0, 67, 70, 70, 0, 0, 116, 116, 118, 97, 1, 0, 0, 0, 1, 209, 77, 0, 190, 0, 1, 0, 0, 0, 1, 2, 0, 36, 151, 154, 158, 155, 255, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 54, 110, 137, 0, 1, 12, 255, 255, 255, 255, 255, 255, 199, 107, 101, 114, 58, 27, 0, 1, 0, 0, 67, 70, 70, 0, 0, 255, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 255, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 1, 82, 97, 114, 115, 98, 105, 136, 0, 255, 66, 66, 76, 0, 193, 17, 0, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 70, 0, 0, 116, 116, 118, 97, 114, 220, 70, 70, 51, 0, 0, 0, 0, 0, 0, 1, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 5, 64, 24, 12, 12, 12, 12, 12, 12, 12, 99, 102, 1, 0, 30, 1, 91, 1, 0, 253, 0, 86, 79, 82, 71, 0, 1, 82, 0, 0, 30, 1, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 205, 0, 0, 1, 0, 0, 210, 1, 0, 0, 255, 255, 255, 199, 107, 101, 114, 110, 82, 1, 63, 169, 173];
if let Ok(font) = fontdue::Font::from_bytes(font, fontdue::FontSettings::default()) {
let (metrics, bitmap) = font.rasterize('g', 17.0);
}
println!("Hello, world!");
}
I'm thinking of using this for my Retro Rust game engine, but if possible I would like to support the BDF font format which seems to be often used for low-resolution bitmap fonts.
Is this out of scope for fontdue?
When doing cargo run --example layout
, I get
error[E0599]: no method named `to_string` found for struct `ttf_parser::tables::name::Name<'_>` in the current scope
--> src/font.rs:212:25
|
212 | return name.to_string();
| ^^^^^^^^^ method not found in `ttf_parser::tables::name::Name<'_>`
I was able to get the samples running by replacing the call to to_string()
with a call to format!()
(for which I had to add #[macro_use] extern crate std;
to lib.rs
), but clearly that is just a kludge.
I noticed that the format of the pixmap doesn't really seem to match what I usually expect. There seems to be no pixel since dimensions of the pixmap are not always multiples of 4.
I am probably missing something. Am I using fontdue correctly?
let mut index = ((x + (y * width as u32)) * 4) as usize;
let font = include_bytes!("/home/bryan/.local/share/fonts/TerminusTTF-Bold.ttf") as &[u8];
// Parse it into the font type.
let font = fontdue::Font::from_bytes(font, fontdue::FontSettings::default()).unwrap();
for c in self.text.chars() {
let (metrics, bitmap) = font.rasterize(c, self.font_size);
for i in (0..metrics.width * metrics.height).into_iter().step_by(metrics.width) {
if index >= canvas.len() {
break;
} else {
let mut writer = &mut canvas[index..];
writer.write(&bitmap[i..i+metrics.width]).unwrap();
writer.flush().unwrap();
index += width as usize * 4;
}
}
}
I just noticed that the documentation for Font::horizontal_line_metrics states:
"The new line height for the font. Only populated for fonts with vertical text layout metrics."
Is the text correct? Does horizontal_line_metrics only work for fonts with 'vertical text layout metrics'? Shouldn't it be 'horizontal text layout metrics'?
Hi @mooman219,
I was try to use your crate in no_std
environment, but without success.
First problem was that the crate has hashbrown = "0.5"
as dependency without disabling default features. It seems if I change hashbrown
version to 0.6 it fixes this issue.
Second problem looks like that in no_std
environment there is no functions like ceil
, floor
, abs
and sqrt
defined for f32
type.
error[E0599]: no method named `ceil` found for type `f32` in the current scope
--> src/font.rs:39:41
|
39 | width: (scale * self.width).ceil() as usize,
| ^^^^
error[E0599]: no method named `ceil` found for type `f32` in the current scope
--> src/font.rs:40:43
|
40 | height: (scale * self.height).ceil() as usize,
| ^^^^
error[E0599]: no method named `ceil` found for type `f32` in the current scope
--> src/raster.rs:70:39
|
70 | for y in y0..min(self.h, p1.y.ceil() as usize) {
| ^^^^
error[E0599]: no method named `floor` found for type `f32` in the current scope
--> src/raster.rs:80:30
|
80 | let x0floor = x0.floor();
| ^^^^^
error[E0599]: no method named `ceil` found for type `f32` in the current scope
--> src/raster.rs:82:29
|
82 | let x1ceil = x1.ceil();
| ^^^^
error[E0599]: no method named `sqrt` found for type `f32` in the current scope
--> src/raster.rs:121:57
|
121 | let n = 1 + (tol * (devx * devx + devy * devy)).sqrt().sqrt().floor() as usize;
| ^^^^
error[E0599]: no method named `abs` found for type `f32` in the current scope
--> src/raster.rs:144:25
|
144 | let y = acc.abs();
| ^^^
error[E0599]: no method named `abs` found for type `f32` in the current scope
--> src/raster.rs:166:25
|
166 | let y = acc.abs();
| ^^^
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0599`.
error: Could not compile `fontdue`.
As far as I can tell from reading the code, this is a simplification step (performed while loading a font) which omits details which would not be visible at smaller sizes. Is that correct?
Related: #60.
Also related: #49. If I wished to render a glyph for multiple sub-pixel positions (e.g. (0, 0)
and (0.5, 0)
— not RGB sub-pixel rendering)... this isn't supported. Does the "outline simplification" above conflict with supporting this?
In Unicode, the same code point can have different glyphs depends on variant selector.
I suggest adding a unicode variant option to Font::lookup_glyph_index()
.
Would it be possible to integrate font-kit in the future as a shaping backend behind a feature flag?
Hello again !
After upgrading my console from version 0.0.4 to 0.1.0 of fontdue, visual quality of the rendered characters significantly degraded.
Here is what it looked like before:
This is what it looks like now:
(I am using font size 15.0 btw)
Certain characters look different, just slightly "denser" or "thinner" in certain areas. This is especially visible on 'o', 'a', 'g' and 'c' characters (mostly the ones that curve apparently).
It traced it back to this commit, fixing the std problem where std ops were used by implementing a custom atan2 fn.
I tried replacing it by copy-pasting the one found in libm, and it fixed this issue, restoring back the look before this commit.
I tried looking for what's wrong in the new code, but I'm not smart enough sadly.
Do you think a fix is possible ?
Thanks again,
Marime Gui
The px
scale units appear to be pixels per Em. This could be clearer in the docs.
If you want inspiration for the docs, see: https://github.com/kas-gui/kas-text/blob/master/src/fonts/mod.rs#L38
Ironically my library exposes scale via "DPU" (pixels for font unit) which is what fontdue uses internally, thus I have to multiply by units-per-em so that fontdue can divide again (in Font::scale_factor
, called by various functions). Not really an issue.
What is the status/are your plans for:
There are unstable APIs for SIMD on platforms like Web, ARM, and POWER. Ideally add a way to utilize this APIs if the user is on nightly.
I'm currently looking for several font libraries available in Rust. One feature I want is to render outlined glyph, as in Glyph Stroker in FreeType (expected output: like this). I looked up the docs for this library but could not find plausible one. Does this library currently support the feature? (Additionally, do you know some other library for Rust that supports this? You don't have to answer this question in the parenthesis)
I hope this doesn't come off as snobbish or anything like that, but I find the code can be hard to read at times. For instance,
pub fn read_utf8(string: &str, byte_offset: &mut usize) -> char {
let bytes = string.as_bytes();
let x = bytes[*byte_offset];
*byte_offset += 1;
if x < 128 {
return unsafe { core::char::from_u32_unchecked(x as u32) };
}
let init = (x & (0x7F >> 2)) as u32;
let y = bytes[*byte_offset];
*byte_offset += 1;
let mut ch = utf8_acc_cont_byte(init, y);
if x >= 0xE0 {
let z = bytes[*byte_offset];
*byte_offset += 1;
let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z);
ch = init << 12 | y_z;
if x >= 0xF0 {
let w = bytes[*byte_offset];
*byte_offset += 1;
ch = (init & 7) << 18 | utf8_acc_cont_byte(y_z, w);
}
}
unsafe { core::char::from_u32_unchecked(ch) }
}
It's a bit hard to read at first glance because of a lack of newlines. I myself would've preferred,
pub fn read_utf8(string: &str, byte_offset: &mut usize) -> char {
let bytes = string.as_bytes();
let x = bytes[*byte_offset];
*byte_offset += 1;
if x < 128 {
return unsafe { core::char::from_u32_unchecked(x as u32) };
}
let init = (x & (0x7F >> 2)) as u32;
let y = bytes[*byte_offset];
*byte_offset += 1;
let mut ch = utf8_acc_cont_byte(init, y);
if x >= 0xE0 {
let z = bytes[*byte_offset];
*byte_offset += 1;
let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z);
ch = init << 12 | y_z;
if x >= 0xF0 {
let w = bytes[*byte_offset];
*byte_offset += 1;
ch = (init & 7) << 18 | utf8_acc_cont_byte(y_z, w);
}
}
unsafe { core::char::from_u32_unchecked(ch) }
}
Of course, this is an entirely subjective and pedantic issue and I apologise if I've offended you in some way, but I really think some degree of separation should be there. Thoughts?
Hello, I'm looking into using fontdue for font atlas rendering, but as far as I can tell, there is no way to enumerate the characters in Font
. I'm wondering what your thoughts on supporting something like that are? I'm happy to do the initial work for that, seems straightforward enough
To reproduce: in the 'simple' example change the constants to SIZE = 0.0
, CHARACTER = 'o'
, FONT = include_bytes!("path to UbuntuMono-Regular.ttf")
. (You can download "UbuntuMono-Regular.ttf" from Google Fonts, GitHub doesn't allow attaching .ttf files to issues).
Program received signal SIGSEGV, Segmentation fault.
0x000055555558b570 in fontdue::raster::Raster::add (self=0x7fffffffcb00, index=18446744071562067968, height=0, mid_x=0) at src/raster.rs:45
45 *self.a.get_unchecked_mut(index) += height - m;
(gdb) bt
#0 0x000055555558b570 in fontdue::raster::Raster::add (self=0x7fffffffcb00, index=18446744071562067968, height=0, mid_x=0) at src/raster.rs:45
#1 fontdue::raster::Raster::m_line (self=0x7fffffffcb00, line=0x5555558a7710, coords=..., params=...) at src/raster.rs:118
#2 fontdue::raster::Raster::draw (self=0x7fffffffcb00, glyph=0x55555567a430, scale_x=0, scale_y=0, offset_x=0, offset_y=0) at src/raster.rs:36
#3 0x000055555558e457 in fontdue::font::Font::rasterize_indexed (self=0x7fffffffcd08, index=82, px=0) at src/font.rs:525
#4 0x0000555555570fb1 in fontdue::font::Font::rasterize (self=0x7fffffffcd08, character=111 'o', px=0) at /home/leshainc/Projects/fontdue/src/font.rs:462
#5 0x000055555556be7b in simple::generate_fontdue () at examples/simple.rs:28
#6 0x000055555556bdc6 in simple::main () at examples/simple.rs:14
I have no idea if this is a concern for your library at all i never opened the source tree even once to see if you use generics at all, but i bet you do
<3
It's better for the long term health of the Rust ecosystem.
You don't need to remove the MIT license though! You could simply add Zlib as an option
license = "MIT OR Zlib"
First-line indentation is very common in typesetting, and looks like this:
The first line starts
further to the right than
the subsequent lines of
text.
It would be wonderful if fontdue could support it, e.g. with a simple first_line_indentation: f32
in LayoutSettings
, especially if this is simple to implement. Of course the setting only makes sense for HorizontalAlign::Left
.
I am writing an immediate mode GUI and this would enable me to seemlessly mix text with others widgets (in a row-based fashion). Basically I would use first_line_indentation
to indicate that I've already used up the first few pixels of the first line (maybe there is a button there or some other text using a different font).
My fuzzer found a hang when attempting to parse the attached font using Font::from_bytes(...)
cargo build --target wasm32-unknown-unknown --release
Compiling fontdue v0.1.2
error[E0432]: unresolved import `crate::platform::float::trunc`
--> /Users/bombfuse/.cargo/registry/src/github.com-1ecc6299db9ec823/fontdue-0.1.2/src/platform/simd_core.rs:3:5
|
3 | use crate::platform::float::trunc;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `trunc` in `platform::float`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0432`.
error: could not compile `fontdue`.
Spanish uses some accented letters that don't exist in English. These include "í" "ó" and "á". Consider the sample string:
¿Cómo estás?
As can be seen when Github+Firefox render this string, the vertical alignment of the accented letters is fine. Yet, when I render this same string using fontdue, the letters are slightly lower than they should be, but only with smaller font sizes.
This is the code that handles the rendering:
fn draw_string(string: &str, x: i32, y: i32, font_size: f32, buffer: &mut Bitmap){
let font = include_bytes!("roboto/Roboto-Regular.ttf") as &[u8];
let mut font = Font::from_bytes(font, FontSettings::default()).unwrap();
let xf = x as f32;
let yf = y as f32;
let mut x_offset: f32 = 0.0;
for c in string.chars(){
let (metrics, bitmap) = font.rasterize(c, font_size);
let xmin = metrics.bounds.xmin;
let ymax = metrics.bounds.ymax;
for cx in 0..metrics.width{
for cy in 0..metrics.height{
let intensity = bitmap[cy*metrics.width+cx];
let x_pos = xf+x_offset+(cx as f32)+xmin;
let y_pos = yf+(cy as f32)- ymax;
if x_pos >= 0.0 && y_pos >= 0.0 {
buffer.set_pixel(x_pos as usize, y_pos as usize, Color::new(intensity, intensity, intensity));
}
}
}
x_offset += metrics.advance_width;
}
}
https://github.com/SolidZORO/zpix-pixel-font/tree/master/dist
Zpix is a pixel font. Standard size is 12px. Is rasterize ok on multiple of 12px.
But in some size the rasterize is incorrect.
For example:
size = 12px
size = 32px
size = 48px
size = 64px
There some lines in bottom.
=================================
https://purestudio.itch.io/ipix
IPix is another pixel font. Recommand size is 12px, but actually is 16px.
size = 12px
size = 16px
size = 48px
size = 64px
=============================
rusttype can rasterize correct, but lost hard edge.
Zpix.ttf
size = 12px
size = 48px
size = 64px
Hi!
I found something strange after updating dependencies for my project recently.
Rust compiler can't build fontdue library with a message:
--> /Users/gerodrus/.cargo/registry/src/github.com-1ecc6299db9ec823/fontdue-0.5.1/src/platform/float/get_bitmap.rs:18:62
|
18 | *(output.get_unchecked_mut(i)) = f32::clamp(f32::abs(height) * 255.9, 0.0, 255.0) as u8;
| ^^^ function or associated item not found in `f32`
rustc version is 1.52.1 with target -- stable-aarch64-apple-darwin (Apple Silicon)
My project is using macroquad library, that depends on fontdue.
If I can provide any further information, feel free to ask.
Hi,
I'm not sure what the intended behavior is here, but when max_width
is set to None
in LayoutSettings
, hard line breaks have no effect. Relevant code:
Line 200 in 3e2f51f
If this is intentional then that's totally fine, I'll specify a relevant maximum width.
Thanks for the great library!
I was trying various fonts included in the Fonts directory on my Mac with the raster-print.rs
example. I tried HelveticaNeue.ttc
and NewYork.ttf
and both produced metrics with a width and height > 0 but the output is totally blank.
(Also happy holidays!🎄🎄🎄)
My fuzzer found a segfault in Raster::draw while calling font.render('g', 60.0)
for the included font file.
segfault2.zip
My fuzzer found a hang while attempting to call font.rasterize('g', 60.0)
on the included font file.
hang_raster.zip
Hello to anyone reading this !
I am in the process of building a Console for a bare-metal PowerPC system (can you guess which one ?) with fontdue 0.0.4 !
When creating the console under native Windows/x64, everything worked just fine, I then copied my code over to my main PPC repo, adapted stuff and tried compiling it...
You might have guessed it didn't go far:
error[E0463]: can't find crate for `std`
--> /home/guillaume/.cargo/registry/src/github.com-1ecc6299db9ec823/hashbrown-0.5.0/src/lib.rs:36:1
|
36 | extern crate std as alloc;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate
|
= note: the `powerpc-none-eabi-2552456384893224483` target may not be installed
Looking at the surrounding code in the repo for hashbrown version 0.5.0, it performs a check for the 'nightly' feature, but fails somehow ?
Anyways, it was apparently fixed in a later release, because trying to cross-compile hashbrown 0.5 on it's own (without fontdue) in a separate crate with minimal code fails just like above, but when raising the version to 0.6 for example the build works just fine.
Cloning fontdue locally and modifying the version to 0.6 fixes the issue with hashbrown, but raises another one: A lot of code in fontdue that uses f32 fns like .powi()
, .ceil()
or .abs()
fails to compile.
I also tried on my native Windows/x64 machine, on a crate WITH std, cloning the repo locally and changing the version of hashbrown to 0.6 raises the same f32 fns issues !
As far as I understand, this bug in hashbrown made the std-only f32 fns available in fontdue's no-std environment, but when upgrading hashbrown, fixing this bug, these features aren't available anymore to fontdue and the build fails, just like one would expect...
So this raises a bit of an issue... Correct me if I am wrong, but the std-only features were used by mistake in developpement of this crate because of that bug ? This is quite the problem for supporting no-std platforms, one of the biggest features of this crate...
Is this really what I think ? I'd be willing to help to fix these issues to get my project back on track !
Thanks,
Marime Gui
It seems like that Fontdue's rasterized characters are just a little smaller than that of Firefox or Chrome. Also, using the Roboto font, the lowercase 'i' is very noticeably different.
I made a little test where I laid my program over Firefox, both using Roboto-Regular, 40px.
It looks like the character advance and line height aren't quite right. Does Fontdue support kerning? Also, will we be able to change the line height in the future? I couldn't find anything related to these in the docs.
TrueType and OpenType need a lot of coverage. Consider upstreaming sanitation changes to ttf input that fontdue does right now into a library dedicated to being a parser.
Post api demands here
Hello again!
I'm running into a few issues which I'm not quite sure how to solve with fontdue's current API. I have an OpenGL glyph renderer and I pass it structs which are very similar to fontdue's TextStyle
, but with a color attribute:
pub type Color = (f32, f32, f32, f32);
pub struct StyledText<'a> {
pub text: &'a str,
pub font: Font, // My own enum, you can ignore this
pub color: (u8, u8, u8, u8),
}
After rasterizing, I have to correlate fontdue's output of GlyphPosition
s back to my original output to determine which color to use for the glyph. I see you added include_whitespace
to support solving this problem, but I'm running into a whitespace issue that makes this a little difficult:
'\n'
will map to the font's fallback character but ' '
will map to a zero-width and zero-height bitmapI need to double check tomorrow, but from my tests the rasterizer seemed to handle it as a missing glyph, here was my debug output when rasterizing and packing into a glyph texture:
# The font is IBM Plex Sans, 300 weight
'あ': Ok(GlyphMissing)
'0': Ok(Packed)
'1': Ok(Packed)
':': Ok(Packed)
'4': Ok(Packed)
'8': Ok(Packed)
'\n': Ok(GlyphMissing)
'F': Ok(Packed)
'P': Ok(Packed)
'S': Ok(Packed)
':': Ok(Packed)
' ': Ok(WhitespaceChar)
'5': Ok(Packed)
'8': Ok(Packed)
I currently keep track of all this with a data structure of type Vec<(Range<usize>, Color)>
, and I use include_whitespace = true
so the character indices line up with the input. Let me know if you're interested in seeing the full code, it's kind of messy and it's a lot of extra work just to correlate the output back to the original input colors.
It all feels a bit fragile though and I'm wondering if you'd be open to possible API changes to make it easier to correlate.
For example, GlyphPosition
could potentially hold an index which points to the TextStyle
it came from.
Or if struct size is an issue, maybe TextStyle
and GlyphPosition
could be generic over a user-provided struct so it could default to a zero-sized struct but also allow us to optionally attach extra data that gets included in the output. Here's a brief example of that.
I could make an attempt at adding this to fontdue if it sounds like something you'd be interested in including in its API, but I just wanted to start a discussion here first. Thanks for the consideration!
No comment
While porting the font renderer for egui to fontdue, I happen to notice that some glyphs are missing the coverage data for a font that egui uses:
https://github.com/emilk/egui/blob/master/egui/fonts/Comfortaa-Regular.ttf
For example the glyph for the character 'b' only has a vector with coverage of "0.0"s, but on the other side, the metrics look fine.
Rusttype doesn't seem to have this problem.
use std::fs::File;
use std::io::Write;
// Scratch pad for glyphs: ⅞ g
const CHARACTER: char = 'g';
const SIZE: f32 = 50.0;
pub fn main() {
// Loading and rasterization
let font = include_bytes!("../resources/Roboto-Regular.ttf") as &[u8];
let font = fontdue::Font::from_bytes(font, fontdue::FontSettings::default()).unwrap();
let metrics_0 = font.metrics(CHARACTER, SIZE, 0.0);
let (metrics, bitmap) = font.rasterize(CHARACTER, SIZE, 0.0);
dbg!(metrics_0);
dbg!(metrics);
// Output
let mut o = File::create("fontdue.pgm").unwrap();
let _ = o.write(format!("P5\n{} {}\n255\n", metrics.width, metrics.height).as_bytes());
let _ = o.write(&bitmap);
}
output:
[examples/simple.rs:15] metrics_0 = Metrics {
width: 23,
height: 38, // <------- this
advance_width: 28.051758,
advance_height: 0.0,
bounds: AABB {
xmin: 2.34375,
xmax: 24.658203,
ymin: -10.400391,
ymax: 26.904297,
},
}
[examples/simple.rs:16] metrics = Metrics {
width: 23,
height: 39, // <------- this
advance_width: 28.051758,
advance_height: 0.0,
bounds: AABB {
xmin: 2.34375,
xmax: 24.658203,
ymin: -10.400391,
ymax: 26.904297,
},
}
Hey, thanks for this blazing fast rasterizer.
While implementing a text drawing backend I found out that I need some more metrics that are currently available in ttf_parser but not exposed in fontdue. Like for example underline/strikeout drawing hints from Face::underline_metrics()
and Face::strikeout_metrics()
. Current workaround is to reparse the same font twice just to get the metrics, which is a bit wasteful since this is done on fontdue already.
I can contribute PR, just wanted to run this by to make sure it's something you want to include in this lib?
When the following font is rasterized with fontdue it is missing the dots above the lowercase i and j.
https://nickmass.com/files/evesansneue-regular.otf
I modified the raster-print example code to render the same font with rusttype/freetype-rs for comparison:
Changing the rasterizing scale has no effect on the problem, and slightly interestingly the exclamation point renders with its dot just fine.
I checked the font against some previous versions of fontdue and noticed that prior to commit cb2e9b2 the problem is actually reversed and it only renders the dot while the stem of the characters is absent.
I added some debugging to the fontdue Geometry struct to see if the glyphs were being loaded correctly and as far as I could tell that was fine.
// fontdue loading the lowercase 'i'
move_to(x0: 75, y0: 540)
line_to(x0: 155, y0: 540)
line_to(x0: 155, y0: 0)
line_to(x0: 75, y0: 0)
close()
move_to(x0: 75, y0: 640)
line_to(x0: 155, y0: 640)
line_to(x0: 155, y0: 720)
line_to(x0: 75, y0: 720)
close()
// results in the following v_lines being created
v_line(start:(155, 540), end:(155, 0))
v_line(start:(75, 0), end:(75, 540))
v_line(start:(155, 640), end:(155, 720))
v_line(start:(75, 720), end:(75, 640))
I removed this from the has because it was a bad hash. Some people liked knowing the character though so I'll add it back.
Hi.
Given the following string:
https://github.com/emilk/egui/blob/a35fe7da126f82dcdf3738a250e150a5ff5d30bb/egui/src/demos/mod.rs#L19
I get the following output (please ignore the miss aligned glyphs for now):
I used the following layout settings:
let settings = LayoutSettings {
max_width: max_width_in_points,
wrap_hard_breaks: true,
..Default::default()
};
Given these settings I would assume that line breaks are honoured and I get an empty line between the paragraphs. It also seems that after the line break, the wrapping isn't working anymore.
Is this the expected behaviour?
Title pretty much says it all. The code that I'm using for layout is basically this, except the ymax variable is floored as soon as it's read to fix the issue that I was having when I posted that code. I'm not sure how much you'll care about this bug, given that proper layout is coming soon (I eagerly await this), but I figured that I should make you aware either way.
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.