Fontdue - The fastest font renderer in the world, written in pure rust.

Overview

Fontdue

Test Documentation Crates.io License

Fontdue is a simple, no_std (does not use the standard library for portability), pure Rust, TrueType (.ttf/.ttc) & OpenType (.otf) font rasterizer and layout tool. It strives to make interacting with fonts as fast as possible, and currently has the lowest end to end latency for a font rasterizer.

Roadmap

Current goal (milestone 1): fontdue is designed to be a replacement for rusttype (link), ab_glyph (link), parts of glyph_brush (link), and glyph_brush_layout (link). This is a class of font libraries that don't tackle shaping.

Future goals: Shaping - the complex layout of text such as Arabic and Devanagari - will be added. There are two potential pure Rust libraries (allsorts or rustybuzz) that are candidates for providing a shaping backend to Fontdue, but are relatively immature right now.

A non-goal of this library is to be allocation free and have a fast, "zero cost" initial load. This library does make allocations and depends on the alloc crate. Fonts are fully parsed on creation and relevant information is stored in a more convenient to access format. Unlike other font libraries, the font structures have no lifetime dependencies since it allocates its own space.

Example

Live demo

Rasterization

The rasterization API is done for milestone 1 and should not see major changes.

// Read the font data.
let font = include_bytes!("../resources/Roboto-Regular.ttf") as &[u8];
// Parse it into the font type.
let font = fontdue::Font::from_bytes(font, fontdue::FontSettings::default()).unwrap();
// Rasterize and get the layout metrics for the letter 'g' at 17px.
let (metrics, bitmap) = font.rasterize('g', 17.0);

Layout

The layout API is immature and may see many more major breaking changes before milestone 1.

). All styles need to share the same // metadata type. let mut layout = Layout::new(CoordinateSystem::PositiveYUp); layout.append(fonts, &TextStyle::with_user_data("Hello ", 35.0, 0, 10u8)); layout.append(fonts, &TextStyle::with_user_data("world!", 40.0, 0, 20u8)); println!("{:?}", layout.glyphs()); ">
// Read the font data.
let font = include_bytes!("../resources/fonts/Roboto-Regular.ttf") as &[u8];
// Parse it into the font type.
let roboto_regular = Font::from_bytes(font, fontdue::FontSettings::default()).unwrap();
// The list of fonts that will be used during layout.
let fonts = &[roboto_regular];
// Create a layout context. Laying out text needs some heap allocations; reusing this context
// reduces the need to reallocate space. We inform layout of which way the Y axis points here.
let mut layout = Layout::new(CoordinateSystem::PositiveYUp);
// By default, layout is initialized with the default layout settings. This call is redundant, but
// demonstrates setting the value with your custom settings.
layout.reset(&LayoutSettings {
    ..LayoutSettings::default()
});
// The text that will be laid out, its size, and the index of the font in the font list to use for
// that section of text.
layout.append(fonts, &TextStyle::new("Hello ", 35.0, 0));
layout.append(fonts, &TextStyle::new("world!", 40.0, 0));
// Prints the layout for "Hello world!"
println!("{:?}", layout.glyphs());

// If you wanted to attached metadata based on the TextStyle to the glyphs returned in the
// glyphs() function, you can use the TextStyle::with_metadata function. In this example, the
// Layout type is now parameterized with u8 (Layout). All styles need to share the same
// metadata type.
let mut layout = Layout::new(CoordinateSystem::PositiveYUp);
layout.append(fonts, &TextStyle::with_user_data("Hello ", 35.0, 0, 10u8));
layout.append(fonts, &TextStyle::with_user_data("world!", 40.0, 0, 20u8));
println!("{:?}", layout.glyphs());

Performance

Rasterization

These benchmarks measure the time it takes to generate the glyph metrics and bitmap for the text "Sphinx of black quartz, judge my vow." over a range of sizes. The lower the line in the graph the better.

Rasterize benchmarks

Rasterize benchmarks

Layout

This benchmark measures the time it takes to layout latin characters of sample text with wrapping on word boundaries.

Layout benchmarks

Notices

Maintenance

Please bear with me on new features or quirks that you find. I will definitely get to issues you open (also thank you for opening them), but I don't have as much time as I would like to work on fontdue so please be patient, this is a mostly solo project <3.

TrueType & OpenType Table Support

Fontdue depends on ttf-parser (link) for parsing fonts, which supports a wide range of TrueType and OpenType features.

Attribution

Fontdue started as a slightly more production ready wrapper around font-rs (link) because of how fast it made rasterization look, and how simple the wonderful rusttype (link) crate made font parsing look. Since then, I've rewritten fontdue from the ground up, but I feel like it still deservers some attribution.

Comments
  • Relicense to `MIT OR Apache-2.0 OR Zlib`

    Relicense to `MIT OR Apache-2.0 OR Zlib`

    As per the discussion in #112, I am initiating the process to relicense this project to the MIT OR Apache-2.0 OR Zlib triple license.

    Rationale for Licensing

    Currently fontdue is licensed solely under MIT. In addition to not being as compatible as it could be with the rest of the ecosystem, most of which uses the MIT OR Apache-2.0 dual license, MIT is also problematic in that in lacks a patent protection clause and an explicit contribution clause. In fact, Rust itself is only keeping around MIT as a licensing option (instead of using just Apache-2.0) for GPLv2 compat.

    If this project were to be dual-licensed under Apache-2.0 and MIT, contributors would be providing the Apache-2.0 patent grant, even though the project will still remain usable with the MIT license. It will also be more compatible with the rest of the ecosystem. Adding a third Zlib licensing option then grants the additional flexibility of not needing to include attribution or license information in product distributions that do not include source code.

    This permissive, flexible, and compatible licensing would be ideal for a crate such as fontdue that is most likely to be used indirectly as dependencies of other crates in its users' dependency graphs.

    Contributor checkoff

    Being a change in license, this requires all contributors who have made copyrightable changes to the fontdue repository to agree.

    For simplicity (and because IANAL), given below is a list of all contributors to the fontdue project. If you agree to relicensing, please comment verbatim:

    I license past and future contributions under the triple MIT OR Apache-2.0 OR Zlib license, allowing licensees to choose any one at their option.

    If you have any concerns, please leave those in this issue thread as well so that they can be discussed.

    • [x] @mooman219
    • [x] @robmcl4
    • [x] @weswigham
    • [x] @twitchyliquid64
    • [x] @Brooooooklyn
    • [x] @ryan-scott-dev
    • [x] @cedric-h
    • [x] @MarimeGui
    • [x] @maroider
    • [x] @Some-Dood
    • [x] @bschwind
    • [x] @tronical
    • [x] @Riey
    • [x] @deeprobin
    • [x] @deprilula28
    • [x] @avl
    • [x] @avafloww
    opened by lunabunn 19
  • Rasterize coarse

    Rasterize coarse

    SourceHanSansSC-Regular.otf on logical 24px(Physical 48px)

    left is ab-glyph, right is fontdue image

    The smaller the size, the more obvious the effect on logical 12px(Physical 24px), this is considered the smallest text size.

    image

    opened by TakWolf 19
  • Add support for inspecting line positions

    Add support for inspecting line positions

    This PR makes it possible for fontdue clients to determine the position of lines of text.

    I needed information about the base line Y-coordinate in order to position the caret in an editable textbox.

    I'm not sure this fits with future plans for fontdue, so feel free to just junk this if it doesn't :-).

    But it was useful for me, and possibly someone else, so I thought I'd create a PR just in case.

    Also, I think there are many ways in which this information could be exposed. If the approach I've implemented here doesn't fit for fontdue, I'd be happy to make adjustments.

    opened by avl 14
  • Some fonts included on Macs rasterize totally blank.

    Some fonts included on Macs rasterize totally blank.

    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!🎄🎄🎄)

    opened by kettle11 14
  • Occurrences of unsafe can be replaced with safe versions

    Occurrences of unsafe can be replaced with safe versions

    I checked a couple of uses of unsafe in this crate and found that they can be replaced with safe versions that generate the same assembly with optimizations. There are probably more instances of this.

    • https://github.com/mooman219/fontdue/blob/c36144652fee3c33f6b763d3171785c5c95816fe/src/platform/float/mod.rs#L35-L39 https://godbolt.org/z/z4x3hEPa3
    • https://github.com/mooman219/fontdue/blob/c36144652fee3c33f6b763d3171785c5c95816fe/src/font.rs#L611-L613 https://godbolt.org/z/hbz5sjhPa

    On that note it is worrying that many uses of unsafe are not documented. I feel their impact should be benchmarked versus safe versions and their correctness should be explained. For example the second link above, with the transmute, seems like undefined behavior to me because I am not sure that Rust guarantees that the layout matches this way.

    documentation 
    opened by e00E 11
  • How to calculate the glyphs layout?

    How to calculate the glyphs layout?

    There is a Metrics struct, but have no baseline info.

        /// Inner bounds of the glyph at the offsets specified by the font.
        pub bounds: AABB,
    

    How to use the bounds?

    image

    ================================

    font.new_line_width() is a fixed value, This has no scale with it?

    bug 
    opened by TakWolf 11
  • API design questions

    API design questions

    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 GlyphPositions 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:

    • When rasterizing, '\n' will map to the font's fallback character but ' ' will map to a zero-width and zero-height bitmap

    I 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!

    enhancement 
    opened by bschwind 10
  • Scale units

    Scale units

    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.

    enhancement 
    opened by dhardy 9
  • Microoptimization: Make some functions const

    Microoptimization: Make some functions const

    Have marked a few functions as const, if that is possible in the stable version.

    So this does not include functions that contain floating point arithmetic or a mut reference.

    criterion Benchmarks

    Before (Branch master)

    layout/fontdue/100      time:   [3.9368 us 3.9979 us 4.0702 us]
    Found 14 outliers among 250 measurements (5.60%)
      10 (4.00%) high mild
      4 (1.60%) high severe
    layout/fontdue/500      time:   [20.980 us 21.243 us 21.535 us]
    Found 20 outliers among 250 measurements (8.00%)
      14 (5.60%) high mild
      6 (2.40%) high severe
    layout/fontdue/1000     time:   [42.722 us 43.300 us 43.956 us]
    Found 27 outliers among 250 measurements (10.80%)
      12 (4.80%) high mild
      15 (6.00%) high severelayout/glyph_brush_layout/100
                            time:   [14.262 us 14.453 us 14.680 us]
    Found 16 outliers among 250 measurements (6.40%)
      9 (3.60%) high mild
      7 (2.80%) high severe
    layout/glyph_brush_layout/500
                            time:   [74.289 us 75.880 us 77.730 us]
    Found 10 outliers among 250 measurements (4.00%)
      7 (2.80%) high mild
      3 (1.20%) high severe
    Benchmarking layout/glyph_brush_layout/1000: Warming up for 3.0000 s
    Warning: Unable to complete 250 samples in 4.0s. You may wish to increase target time to 4.6s, enable flat sampling, or reduce sample count to 160.
    layout/glyph_brush_layout/1000
                            time:   [144.82 us 147.18 us 149.85 us]
    Found 27 outliers among 250 measurements (10.80%)
      16 (6.40%) high mild
      11 (4.40%) high severe     Running unittests (target\release\deps\load-1ebd4c7446ed2dd1.exe)
    WARNING: HTML report generation will become a non-default optional feature in Criterion.rs 0.4.0.
    This feature is being moved to cargo-criterion (https://github.com/bheisler/cargo-criterion) and will be optional in a future version of Criterion.rs. To silence this warning, either switch to cargo-criterion or enable the 'html_reports' feature in your Cargo.toml.Gnuplot not found, using plotters backend
    load/rusttype roboto    time:   [894.43 ns 909.01 ns 924.52 ns]
    Found 12 outliers among 100 measurements (12.00%)
      6 (6.00%) high mild
      6 (6.00%) high severe
    load/ab_glyph roboto    time:   [1.0128 us 1.0385 us 1.0705 us]
    Found 9 outliers among 100 measurements (9.00%)
      2 (2.00%) high mild
      7 (7.00%) high severe
    load/fontdue roboto     time:   [4.1027 ms 4.1663 ms 4.2406 ms]
    Found 9 outliers among 100 measurements (9.00%)
      6 (6.00%) high mild
      3 (3.00%) high severe     Running unittests (target\release\deps\rasterize-6f6795b8152ccfd3.exe)
    WARNING: HTML report generation will become a non-default optional feature in Criterion.rs 0.4.0.
    This feature is being moved to cargo-criterion (https://github.com/bheisler/cargo-criterion) and will be optional in a future version of Criterion.rs. To silence this warning, either switch to cargo-criterion or enable the 'html_reports' feature in your Cargo.toml.Gnuplot not found, using plotters backend
    rasterize/rusttype truetype 10px
                            time:   [52.563 us 53.613 us 54.892 us]
    Found 12 outliers among 100 measurements (12.00%)
      5 (5.00%) high mild
      7 (7.00%) high severe
    rasterize/rusttype truetype 20px
                            time:   [70.946 us 71.995 us 73.158 us]
    Found 7 outliers among 100 measurements (7.00%)
      5 (5.00%) high mild
      2 (2.00%) high severe
    rasterize/rusttype truetype 40px
                            time:   [121.94 us 123.44 us 125.13 us]
    Found 12 outliers among 100 measurements (12.00%)
      7 (7.00%) high mild
      5 (5.00%) high severe
    rasterize/rusttype truetype 80px
                            time:   [254.45 us 258.14 us 262.78 us]
    Found 9 outliers among 100 measurements (9.00%)
      5 (5.00%) high mild
      4 (4.00%) high severe
    rasterize/rusttype truetype 160px
                            time:   [736.76 us 743.05 us 749.93 us]
    Found 10 outliers among 100 measurements (10.00%)
      9 (9.00%) high mild
      1 (1.00%) high severe
    Benchmarking rasterize/rusttype truetype 200px: Warming up for 3.0000 s
    Warning: Unable to complete 100 samples in 4.0s. You may wish to increase target time to 5.5s, enable flat sampling, or reduce sample count to 60.
    rasterize/rusttype truetype 200px
                            time:   [1.0651 ms 1.0735 ms 1.0841 ms]
    Found 6 outliers among 100 measurements (6.00%)
      4 (4.00%) high mild
      2 (2.00%) high severe
    rasterize/rusttype opentype 10px
                            time:   [73.679 us 75.298 us 77.094 us]
    Found 6 outliers among 100 measurements (6.00%)
      4 (4.00%) high mild
      2 (2.00%) high severe
    rasterize/rusttype opentype 20px
                            time:   [92.924 us 94.812 us 96.898 us]
    Found 8 outliers among 100 measurements (8.00%)
      7 (7.00%) high mild
      1 (1.00%) high severe
    rasterize/rusttype opentype 40px
                            time:   [144.18 us 147.56 us 151.42 us]
    Found 6 outliers among 100 measurements (6.00%)
      5 (5.00%) high mild
      1 (1.00%) high severe
    rasterize/rusttype opentype 80px
                            time:   [287.16 us 292.25 us 298.09 us]
    Found 12 outliers among 100 measurements (12.00%)
      4 (4.00%) high mild
      8 (8.00%) high severe
    Benchmarking rasterize/rusttype opentype 160px: Warming up for 3.0000 s
    Warning: Unable to complete 100 samples in 4.0s. You may wish to increase target time to 4.0s, enable flat sampling, or reduce sample count to 70.
    rasterize/rusttype opentype 160px
                            time:   [781.97 us 791.54 us 802.82 us]
    Found 10 outliers among 100 measurements (10.00%)
      6 (6.00%) high mild
      4 (4.00%) high severe
    Benchmarking rasterize/rusttype opentype 200px: Warming up for 3.0000 s
    Warning: Unable to complete 100 samples in 4.0s. You may wish to increase target time to 5.8s, enable flat sampling, or reduce sample count to 50.
    rasterize/rusttype opentype 200px
                            time:   [1.1246 ms 1.1375 ms 1.1534 ms]
    Found 11 outliers among 100 measurements (11.00%)
      7 (7.00%) high mild
      4 (4.00%) high severe
    rasterize/ab_glyph truetype 10px
                            time:   [70.340 us 71.803 us 73.616 us]
    Found 5 outliers among 100 measurements (5.00%)
      4 (4.00%) high mild
      1 (1.00%) high severe
    rasterize/ab_glyph truetype 20px
                            time:   [88.384 us 89.413 us 90.523 us]
    Found 7 outliers among 100 measurements (7.00%)
      4 (4.00%) high mild
      3 (3.00%) high severe
    rasterize/ab_glyph truetype 40px
                            time:   [142.69 us 145.48 us 148.57 us]
    Found 7 outliers among 100 measurements (7.00%)
      3 (3.00%) high mild
      4 (4.00%) high severe
    rasterize/ab_glyph truetype 80px
                            time:   [282.32 us 287.58 us 294.43 us]
    Found 5 outliers among 100 measurements (5.00%)
      4 (4.00%) high mild
      1 (1.00%) high severe
    rasterize/ab_glyph truetype 160px
                            time:   [769.58 us 778.66 us 788.26 us]
    Found 4 outliers among 100 measurements (4.00%)
      3 (3.00%) high mild
      1 (1.00%) high severe
    Benchmarking rasterize/ab_glyph truetype 200px: Warming up for 3.0000 s
    Warning: Unable to complete 100 samples in 4.0s. You may wish to increase target time to 5.7s, enable flat sampling, or reduce sample count to 50.
    rasterize/ab_glyph truetype 200px
                            time:   [1.0970 ms 1.1072 ms 1.1189 ms]
    Found 3 outliers among 100 measurements (3.00%)
      2 (2.00%) high mild
      1 (1.00%) high severe
    rasterize/ab_glyph opentype 10px
                            time:   [90.433 us 93.300 us 96.781 us]
    Found 4 outliers among 100 measurements (4.00%)
      1 (1.00%) high mild
      3 (3.00%) high severe
    rasterize/ab_glyph opentype 20px
                            time:   [83.210 us 84.901 us 87.019 us]
    Found 11 outliers among 100 measurements (11.00%)
      6 (6.00%) high mild
      5 (5.00%) high severe
    rasterize/ab_glyph opentype 40px
                            time:   [135.41 us 137.98 us 140.95 us]
    Found 7 outliers among 100 measurements (7.00%)
      3 (3.00%) high mild
      4 (4.00%) high severe
    rasterize/ab_glyph opentype 80px
                            time:   [279.60 us 284.92 us 291.71 us]
    Found 7 outliers among 100 measurements (7.00%)
      3 (3.00%) high mild
      4 (4.00%) high severe
    rasterize/ab_glyph opentype 160px
                            time:   [774.97 us 782.57 us 791.16 us]
    Found 8 outliers among 100 measurements (8.00%)
      4 (4.00%) high mild
      4 (4.00%) high severe
    Benchmarking rasterize/ab_glyph opentype 200px: Warming up for 3.0000 s
    Warning: Unable to complete 100 samples in 4.0s. You may wish to increase target time to 5.7s, enable flat sampling, or reduce sample count to 50.
    rasterize/ab_glyph opentype 200px
                            time:   [1.1276 ms 1.1442 ms 1.1628 ms]
    Found 6 outliers among 100 measurements (6.00%)
      4 (4.00%) high mild
      2 (2.00%) high severe
    rasterize/fontdue truetype 10px
                            time:   [13.000 us 13.315 us 13.692 us]
    Found 7 outliers among 100 measurements (7.00%)
      2 (2.00%) high mild
      5 (5.00%) high severe
    rasterize/fontdue truetype 20px
                            time:   [24.334 us 24.611 us 24.923 us]
    Found 8 outliers among 100 measurements (8.00%)
      6 (6.00%) high mild
      2 (2.00%) high severe
    rasterize/fontdue truetype 40px
                            time:   [26.627 us 27.122 us 27.716 us]
    Found 11 outliers among 100 measurements (11.00%)
      3 (3.00%) high mild
      8 (8.00%) high severe
    rasterize/fontdue truetype 80px
                            time:   [57.133 us 58.759 us 60.594 us]
    Found 8 outliers among 100 measurements (8.00%)
      6 (6.00%) high mild
      2 (2.00%) high severe
    rasterize/fontdue truetype 160px
                            time:   [165.12 us 171.35 us 178.09 us]
    Found 3 outliers among 100 measurements (3.00%)
      2 (2.00%) high mild
      1 (1.00%) high severe
    rasterize/fontdue truetype 200px
                            time:   [220.03 us 224.26 us 228.85 us]
    Found 2 outliers among 100 measurements (2.00%)
      2 (2.00%) high mild
    rasterize/fontdue opentype 10px
                            time:   [14.551 us 14.901 us 15.325 us]
    Found 11 outliers among 100 measurements (11.00%)
      3 (3.00%) high mild
      8 (8.00%) high severe
    rasterize/fontdue opentype 20px
                            time:   [17.753 us 18.219 us 18.799 us]
    Found 11 outliers among 100 measurements (11.00%)
      5 (5.00%) high mild
      6 (6.00%) high severe
    rasterize/fontdue opentype 40px
                            time:   [30.263 us 31.043 us 31.994 us]
    Found 5 outliers among 100 measurements (5.00%)
      4 (4.00%) high mild
      1 (1.00%) high severe
    rasterize/fontdue opentype 80px
                            time:   [53.996 us 55.609 us 57.353 us]
    Found 9 outliers among 100 measurements (9.00%)
      4 (4.00%) high mild
      5 (5.00%) high severe
    rasterize/fontdue opentype 160px
                            time:   [165.43 us 171.82 us 178.74 us]
    Found 5 outliers among 100 measurements (5.00%)
      4 (4.00%) high mild
      1 (1.00%) high severe
    rasterize/fontdue opentype 200px
                            time:   [206.67 us 210.05 us 213.75 us]
    Found 5 outliers among 100 measurements (5.00%)
      2 (2.00%) high mild
      3 (3.00%) high severe
    

    After (Branch code-optimization)

    layout/fontdue/100      time:   [4.3643 us 4.4218 us 4.4931 us]
    Found 29 outliers among 250 measurements (11.60%)
      16 (6.40%) high mild
      13 (5.20%) high severe
    layout/fontdue/500      time:   [23.136 us 23.396 us 23.681 us]
    Found 18 outliers among 250 measurements (7.20%)
      12 (4.80%) high mild
      6 (2.40%) high severe
    layout/fontdue/1000     time:   [46.804 us 47.228 us 47.713 us]
    Found 19 outliers among 250 measurements (7.60%)
      15 (6.00%) high mild
      4 (1.60%) high severelayout/glyph_brush_layout/100
                            time:   [14.549 us 14.788 us 15.061 us]
    Found 31 outliers among 250 measurements (12.40%)
      15 (6.00%) high mild
      16 (6.40%) high severe
    layout/glyph_brush_layout/500
                            time:   [73.153 us 73.955 us 74.840 us]
    Found 21 outliers among 250 measurements (8.40%)
      13 (5.20%) high mild
      8 (3.20%) high severe
    Benchmarking layout/glyph_brush_layout/1000: Warming up for 3.0000 s
    Warning: Unable to complete 250 samples in 4.0s. You may wish to increase target time to 4.7s, enable flat sampling, or reduce sample count to 160.
    layout/glyph_brush_layout/1000
                            time:   [145.95 us 148.79 us 152.17 us]
    Found 31 outliers among 250 measurements (12.40%)
      9 (3.60%) high mild
      22 (8.80%) high severe     Running unittests (target\release\deps\load-1ebd4c7446ed2dd1.exe)
    WARNING: HTML report generation will become a non-default optional feature in Criterion.rs 0.4.0.
    This feature is being moved to cargo-criterion (https://github.com/bheisler/cargo-criterion) and will be optional in a future version of Criterion.rs. To silence this warning, either switch to cargo-criterion or enable the 'html_reports' feature in your Cargo.toml.Gnuplot not found, using plotters backend
    load/rusttype roboto    time:   [881.63 ns 900.26 ns 922.12 ns]
    Found 9 outliers among 100 measurements (9.00%)
      4 (4.00%) high mild
      5 (5.00%) high severe
    load/ab_glyph roboto    time:   [990.41 ns 1.0091 us 1.0316 us]
    Found 10 outliers among 100 measurements (10.00%)
      5 (5.00%) high mild
      5 (5.00%) high severe
    load/fontdue roboto     time:   [4.4020 ms 4.4644 ms 4.5320 ms]
    Found 8 outliers among 100 measurements (8.00%)
      6 (6.00%) high mild
      2 (2.00%) high severe     Running unittests (target\release\deps\rasterize-6f6795b8152ccfd3.exe)
    WARNING: HTML report generation will become a non-default optional feature in Criterion.rs 0.4.0.
    This feature is being moved to cargo-criterion (https://github.com/bheisler/cargo-criterion) and will be optional in a future version of Criterion.rs. To silence this warning, either switch to cargo-criterion or enable the 'html_reports' feature in your Cargo.toml.Gnuplot not found, using plotters backend
    rasterize/rusttype truetype 10px
                            time:   [51.405 us 52.240 us 53.267 us]
    Found 6 outliers among 100 measurements (6.00%)
      1 (1.00%) high mild
      5 (5.00%) high severe
    rasterize/rusttype truetype 20px
                            time:   [71.044 us 71.931 us 72.982 us]
    Found 8 outliers among 100 measurements (8.00%)
      4 (4.00%) high mild
      4 (4.00%) high severe
    rasterize/rusttype truetype 40px
                            time:   [125.07 us 127.42 us 130.69 us]
    Found 4 outliers among 100 measurements (4.00%)
      1 (1.00%) high mild
      3 (3.00%) high severe
    rasterize/rusttype truetype 80px
                            time:   [256.21 us 259.25 us 263.01 us]
    Found 5 outliers among 100 measurements (5.00%)
      4 (4.00%) high mild
      1 (1.00%) high severe
    rasterize/rusttype truetype 160px
                            time:   [734.03 us 738.59 us 743.83 us]
    Found 10 outliers among 100 measurements (10.00%)
      4 (4.00%) high mild
      6 (6.00%) high severe
    Benchmarking rasterize/rusttype truetype 200px: Warming up for 3.0000 s
    Warning: Unable to complete 100 samples in 4.0s. You may wish to increase target time to 5.4s, enable flat sampling, or reduce sample count to 60.
    rasterize/rusttype truetype 200px
                            time:   [1.0666 ms 1.0737 ms 1.0818 ms]
    Found 6 outliers among 100 measurements (6.00%)
      4 (4.00%) high mild
      2 (2.00%) high severe
    rasterize/rusttype opentype 10px
                            time:   [72.672 us 74.957 us 77.553 us]
    Found 12 outliers among 100 measurements (12.00%)
      6 (6.00%) high mild
      6 (6.00%) high severe
    rasterize/rusttype opentype 20px
                            time:   [92.580 us 93.683 us 94.929 us]
    Found 9 outliers among 100 measurements (9.00%)
      3 (3.00%) high mild
      6 (6.00%) high severe
    rasterize/rusttype opentype 40px
                            time:   [143.39 us 147.03 us 151.34 us]
    Found 13 outliers among 100 measurements (13.00%)
      9 (9.00%) high mild
      4 (4.00%) high severe
    rasterize/rusttype opentype 80px
                            time:   [287.46 us 291.36 us 295.52 us]
    Found 12 outliers among 100 measurements (12.00%)
      6 (6.00%) high mild
      6 (6.00%) high severe
    rasterize/rusttype opentype 160px
                            time:   [778.09 us 785.46 us 794.68 us]
    Found 10 outliers among 100 measurements (10.00%)
      5 (5.00%) high mild
      5 (5.00%) high severe
    Benchmarking rasterize/rusttype opentype 200px: Warming up for 3.0000 s
    Warning: Unable to complete 100 samples in 4.0s. You may wish to increase target time to 5.7s, enable flat sampling, or reduce sample count to 50.
    rasterize/rusttype opentype 200px
                            time:   [1.1217 ms 1.1321 ms 1.1455 ms]
    Found 5 outliers among 100 measurements (5.00%)
      3 (3.00%) high mild
      2 (2.00%) high severe
    rasterize/ab_glyph truetype 10px
                            time:   [70.629 us 72.246 us 74.203 us]
    Found 6 outliers among 100 measurements (6.00%)
      4 (4.00%) high mild
      2 (2.00%) high severe
    rasterize/ab_glyph truetype 20px
                            time:   [90.244 us 92.038 us 94.215 us]
    Found 6 outliers among 100 measurements (6.00%)
      3 (3.00%) high mild
      3 (3.00%) high severe
    rasterize/ab_glyph truetype 40px
                            time:   [140.04 us 141.98 us 144.43 us]
    Found 15 outliers among 100 measurements (15.00%)
      6 (6.00%) high mild
      9 (9.00%) high severe
    rasterize/ab_glyph truetype 80px
                            time:   [282.09 us 285.94 us 290.44 us]
    Found 10 outliers among 100 measurements (10.00%)
      7 (7.00%) high mild
      3 (3.00%) high severe
    rasterize/ab_glyph truetype 160px
                            time:   [747.87 us 753.43 us 759.84 us]
    Found 7 outliers among 100 measurements (7.00%)
      6 (6.00%) high mild
      1 (1.00%) high severe
    Benchmarking rasterize/ab_glyph truetype 200px: Warming up for 3.0000 s
    Warning: Unable to complete 100 samples in 4.0s. You may wish to increase target time to 5.5s, enable flat sampling, or reduce sample count to 50.
    rasterize/ab_glyph truetype 200px
                            time:   [1.0902 ms 1.0992 ms 1.1087 ms]
    Found 3 outliers among 100 measurements (3.00%)
      3 (3.00%) high mild
    rasterize/ab_glyph opentype 10px
                            time:   [63.984 us 65.677 us 67.730 us]
    Found 8 outliers among 100 measurements (8.00%)
      4 (4.00%) high mild
      4 (4.00%) high severe
    rasterize/ab_glyph opentype 20px
                            time:   [83.610 us 85.011 us 86.719 us]
    Found 13 outliers among 100 measurements (13.00%)
      9 (9.00%) high mild
      4 (4.00%) high severe
    rasterize/ab_glyph opentype 40px
                            time:   [132.84 us 134.58 us 136.66 us]
    Found 7 outliers among 100 measurements (7.00%)
      6 (6.00%) high mild
      1 (1.00%) high severe
    rasterize/ab_glyph opentype 80px
                            time:   [284.74 us 292.98 us 302.85 us]
    Found 9 outliers among 100 measurements (9.00%)
      3 (3.00%) high mild
      6 (6.00%) high severe
    rasterize/ab_glyph opentype 160px
                            time:   [765.39 us 770.66 us 776.43 us]
    Found 8 outliers among 100 measurements (8.00%)
      6 (6.00%) high mild
      2 (2.00%) high severe
    Benchmarking rasterize/ab_glyph opentype 200px: Warming up for 3.0000 s
    Warning: Unable to complete 100 samples in 4.0s. You may wish to increase target time to 5.7s, enable flat sampling, or reduce sample count to 50.
    rasterize/ab_glyph opentype 200px
                            time:   [1.1085 ms 1.1182 ms 1.1300 ms]
    Found 6 outliers among 100 measurements (6.00%)
      2 (2.00%) high mild
      4 (4.00%) high severe
    rasterize/fontdue truetype 10px
                            time:   [35.574 us 36.151 us 36.750 us]
    Found 10 outliers among 100 measurements (10.00%)
      5 (5.00%) high mild
      5 (5.00%) high severe
    rasterize/fontdue truetype 20px
                            time:   [20.003 us 20.317 us 20.706 us]
    Found 8 outliers among 100 measurements (8.00%)
      6 (6.00%) high mild
      2 (2.00%) high severe
    rasterize/fontdue truetype 40px
                            time:   [27.129 us 27.646 us 28.238 us]
    Found 9 outliers among 100 measurements (9.00%)
      4 (4.00%) high mild
      5 (5.00%) high severe
    rasterize/fontdue truetype 80px
                            time:   [60.512 us 62.464 us 64.809 us]
    Found 7 outliers among 100 measurements (7.00%)
      1 (1.00%) high mild
      6 (6.00%) high severe
    rasterize/fontdue truetype 160px
                            time:   [152.80 us 155.76 us 158.95 us]
    Found 2 outliers among 100 measurements (2.00%)
      1 (1.00%) high mild
      1 (1.00%) high severe
    rasterize/fontdue truetype 200px
                            time:   [213.14 us 216.81 us 220.91 us]
    Found 3 outliers among 100 measurements (3.00%)
      3 (3.00%) high severe
    rasterize/fontdue opentype 10px
                            time:   [11.939 us 12.163 us 12.434 us]
    Found 10 outliers among 100 measurements (10.00%)
      4 (4.00%) high mild
      6 (6.00%) high severe
    rasterize/fontdue opentype 20px
                            time:   [17.800 us 18.161 us 18.581 us]
    Found 5 outliers among 100 measurements (5.00%)
      2 (2.00%) high mild
      3 (3.00%) high severe
    rasterize/fontdue opentype 40px
                            time:   [29.286 us 29.723 us 30.208 us]
    Found 8 outliers among 100 measurements (8.00%)
      4 (4.00%) high mild
      4 (4.00%) high severe
    rasterize/fontdue opentype 80px
                            time:   [57.324 us 58.598 us 60.133 us]
    Found 12 outliers among 100 measurements (12.00%)
      2 (2.00%) high mild
      10 (10.00%) high severe
    rasterize/fontdue opentype 160px
                            time:   [149.25 us 152.62 us 156.81 us]
    Found 10 outliers among 100 measurements (10.00%)
      5 (5.00%) high mild
      5 (5.00%) high severe
    rasterize/fontdue opentype 200px
                            time:   [207.22 us 212.67 us 219.20 us]
    Found 9 outliers among 100 measurements (9.00%)
      7 (7.00%) high mild
      2 (2.00%) high severe
    

    Comparison

    opened by deeprobin 8
  • The letter

    The letter "u" does not align correctly.

    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.

    image

    opened by john01dav 8
  • Spanish letters misaligned with font sizes smaller than ~22

    Spanish letters misaligned with font sizes smaller than ~22

    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.

    Font size 12: image

    Font size 17: image

    Font size 22: image

    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;
        }
    }
    
    opened by john01dav 8
  • Font line metrics don't match character metrics

    Font line metrics don't match character metrics

    Heyo!

    I'm trying to do some basic font rendering. As part of testing I started iterating over each character in Inconsolata and rendering each one. Just a couple of characters in, I tried to render (index 4), and it failed, seemingly because when rasterized it reaches higher than the ascent reported in the horizontal line metrics (char height=18.04, line ascent=17.18)

    I'm not sure if my code is broken because I don't understand fonts, if the font has a slight bug, or if fontdue has an issue, so I've also attached the code I discovered this with and the TTF file (zipped to make GitHub happy). In brief:

    • I'm using line_metrics.ascent.ceil() as usize + line_metrics.descent.floor() as usize to decide how tall each row is.
    • Then, when I rasterize, I'm doing line_metrics.ascent.ceil() as usize - char_metrics.ymin + char_metrics.height (with some casts to ensure the math can be done) to get the number of rows between the top of the rasterized buffer and the top of the line.
    • But that math is failing -- again, as far as I can tell, because ymin == 0, and the character's rasterized height is greater than the line's ascent.

    So my questions are: Is my math just wrong? (If so, what's the right way to do this?) Otherwise, is this an issue with this font specifically, and what would be the nicest way to work around it?

    opened by nic-hartley 0
  • Rasterize a whole string

    Rasterize a whole string

    Hi, I'm making a wordcloud program and I'd like to be able to convert a whole string such as "Hello world" to a bitmap directly, like we can already do with individual chars.
    Could this be added to fontdue ?

    If this feature is out of scope for the library could you help me in implementing that ?
    I'm lost in all the Layout and Metrics parameters and I'm not sure how to interpret them, especially the negative xmin and ymin of Metrics.

    opened by Inspirateur 0
  • Ligature support- pairing with other libraries

    Ligature support- pairing with other libraries

    As best I can tell, ligatures aren't supported now in fontdue. Is there a recommended library to pair with fontdue for proper shaping? I'm looking at other libraries like swash, but it's not clear to me how their features overlap or complement fontdue.

    opened by leecbaker 0
  • SDF texture generation

    SDF texture generation

    Would it make sense to also add SDF font generation to fontdue?

    This would allow easier zooming/rotation of text when paired with the right shader, and maybe also reduce the size of the glyph texture atlas.

    opened by Dimev 0
  • can fontdue rasterize with fractional pixel offsets?

    can fontdue rasterize with fractional pixel offsets?

    I don't see anything in the API, but perhaps I'm missing it?

    I don't need RGB subpixel AA (and indeed I don't think it would work well with my glyph atlas approach, especially when text is transformed), but it would be nice to rasterize with subpixel offsets.

    I'm using fontdue in this library which is used in my little GUI library

    opened by wtholliday 2
Owner
Joe C
fonts
Joe C
This library is a pull parser for CommonMark, written in Rust

This library is a pull parser for CommonMark, written in Rust. It comes with a simple command-line tool, useful for rendering to HTML, and is also designed to be easy to use from as a library.

Raph Levien 1.5k Jan 1, 2023
CLI tool to convert HOCON into valid JSON or YAML written in Rust.

{hocon:vert} CLI Tool to convert HOCON into valid JSON or YAML. Under normal circumstances this is mostly not needed because hocon configs are parsed

Mathias Oertel 23 Jan 6, 2023
JSON parser which picks up values directly without performing tokenization in Rust

Pikkr JSON parser which picks up values directly without performing tokenization in Rust Abstract Pikkr is a JSON parser which picks up values directl

Pikkr 615 Dec 29, 2022
Strongly typed JSON library for Rust

Serde JSON   Serde is a framework for serializing and deserializing Rust data structures efficiently and generically. [dependencies] serde_json = "1.0

null 3.6k Jan 5, 2023
Rust port of simdjson

SIMD Json for Rust   Rust port of extremely fast simdjson JSON parser with serde compatibility. readme (for real!) simdjson version Currently tracking

null 737 Dec 30, 2022
JSON implementation in Rust

json-rust Parse and serialize JSON with ease. Changelog - Complete Documentation - Cargo - Repository Why? JSON is a very loose format where anything

Maciej Hirsz 500 Dec 21, 2022
Rust port of gjson,get JSON value by dotpath syntax

A-JSON Read JSON values quickly - Rust JSON Parser change name to AJSON, see issue Inspiration comes from gjson in golang Installation Add it to your

Chen Jiaju 90 Dec 6, 2022
Get JSON values quickly - JSON parser for Rust

get json values quickly GJSON is a Rust crate that provides a fast and simple way to get values from a json document. It has features such as one line

Josh Baker 160 Dec 29, 2022
A rust script to convert a better bibtex json file from Zotero into nice organised notes in Obsidian

Zotero to Obsidian script This is a script that takes a better bibtex JSON file exported by Zotero and generates an organised collection of reference

Sashin Exists 3 Oct 9, 2022
Typify - Compile JSON Schema documents into Rust types.

Typify Compile JSON Schema documents into Rust types. This can be used ... via the macro import_types!("types.json") to generate Rust types directly i

Oxide Computer Company 73 Dec 27, 2022
A easy and declarative way to test JSON input in Rust.

assert_json A easy and declarative way to test JSON input in Rust. assert_json is a Rust macro heavily inspired by serde json macro. Instead of creati

Charles Vandevoorde 8 Dec 5, 2022
Hjson for Rust

hjson-rust for serde { # specify rate in requests/second (because comments are helpful!) rate: 1000 // prefer c-style comments? /* feeling ol

Hjson 83 Oct 5, 2022
A small rust database that uses json in memory.

Tiny Query Database (TQDB) TQDB is a small library for creating a query-able database that is encoded with json. The library is well tested (~96.30% c

Kace Cottam 2 Jan 4, 2022
A JSON Query Language CLI tool built with Rust 🦀

JQL A JSON Query Language CLI tool built with Rust ?? ?? Core philosophy ?? Stay lightweight ?? Keep its features as simple as possible ?? Avoid redun

Davy Duperron 872 Jan 1, 2023
An implementation of the JSONPath A spec in Rust, with several extensions added on

Rust JSONPath Plus An implementation of the JSONPath A spec in Rust, with several extensions added on. This library also supports retrieving AST analy

Rune Tynan 4 Jul 13, 2022
An HCL serializer/deserializer for rust

hcl-rs This crate provides functionality to deserialize, serialize and manipulate HCL data. The main types are Deserializer for deserializing data, Se

null 56 Dec 31, 2022
Rust libraries and tools to help with interoperability and testing of serialization formats based on Serde.

The repository zefchain/serde-reflection is based on Facebook's repository novifinancial/serde-reflection. We are now maintaining the project here and

Zefchain Labs 46 Dec 22, 2022
Blazing fast Rust JSONPath query engine.

rsonpath – SIMD-powered JSONPath ?? Experimental JSONPath engine for querying massive streamed datasets. Features The rsonpath crate provides a JSONPa

V0ldek 21 Apr 11, 2023
A Rust program that analyzes your TikTok data.

The TikTok JSON analyzer This is a program to analyze your TikTok data and calculate these statistics : Number of logins (in the last 6 months) and lo

Elazrod56 3 May 2, 2023