A Rust OpenType manipulation library

Related tags


fonttools-rs   Build Status Latest Version Docs badge

This is an attempt to write an Rust library to read, manipulate and write TTF/OTF files. It is in the early stages of development. Contributions are welcome.

Example usage

use fonttools::font::{self, Font, Table};
use fonttools::name::{name, NameRecord, NameRecordID};

// Load a font (tables are lazy-loaded)
let fontfile = File::open("Test.otf").unwrap();
use std::fs::File;
let mut myfont = font::load(fontfile).expect("Could not load font");

// Access an existing table
if let Table::Name(name_table) = myfont.get_table(b"name")
        .expect("Error reading name table")
        .expect("There was no name table") {
        // Manipulate the table (table-specific)
let mut outfile = File::create("Test-with-OFL.otf").expect("Could not create file");
myfont.save(&mut outfile);

See the documentation for more details, and the fonttools-cli utilities (installable via cargo install fonttools_cli) for code examples.



  • I really don't understand serde custom deserialization

    I really don't understand serde custom deserialization

    I need to write a custom deserializer for Counted in types.rs and I just don't know how to do it. :-/

    opened by simoncozens 13
  • Calculate Code Page ranges

    Calculate Code Page ranges

    Still mega wip. I'm basing my implementation on ufo2ft which in turn is based on FontForge.

    opened by m4rc1e 10
  • consider moving off of nightly

    consider moving off of nightly

    There aren't a lot of great reasons to require nightly rust anymore, and it will be a major barrier to the adoption of this crate elsewhere in the ecosystem. Unless there's a really compelling reason to require nightly, I think it probably makes sense to try and move off of it sooner rather than later, as it will become harder the more nightly features end up being used.

    Any thoughts on this? Last I checked nightly was only being used to improve diagnostics in some derive macros, and there are reasonable workarounds there. Are there any other major motivations?

    It's worth keeping in mind that we can still conditionally use nightly features, enabling them only when we're on a nightly compiler.

    opened by cmyr 9
  • fontcrunch is slow because I can't handle references and lifetimes

    fontcrunch is slow because I can't handle references and lifetimes

    The ported version of fontcrunch is much slower than the original, particularly in glyphs which go down this O(n^2) loop:


    I'm sure it's because of this clone:


    The clone is only there because I can't work out the lifetimes required for storing Statelets as references within a Statelet and moving them around. If I put what I think are the right lifetimes on the State and Statelet types, I get a confusing error like so:

    431 |     states: &mut Vec<State>,
        |             --------------- these two types are declared with different lifetimes...
    454 |         states[this].sts.push(sl);
        |                               ^^ ...but data from `states` flows into `states` here
    opened by simoncozens 8
  • Consider ripping out serde and doing our own ser/deserialization

    Consider ripping out serde and doing our own ser/deserialization

    serde is really good, and really helpful. It's got us very far very quickly. But it has some significant frustrations, most notably the fact that it's not designed for random access.

    Currently any structure that involves offsets (and now we're coming into handling layout, there are lots of them) requires a nasty process of reading the offset data, reading the rest of the structure, calculating how many bytes we've consumed so far in the structure, reading the rest of the available data into a vec, making a new slice starting of the available data from (offset - where we are), and passing that new slice to a separate deserializer. Serializing structs with offsets is even harder, and involves pulling together (possibly nested) serializations and computing their length, etc. The worse thing is that this all has to be done by hand for each structure. If we had true random access, most of the manual ser/de implementations would go away.

    Realistically, we don't need the structure/data format abstraction that serde provides, as we are hardly likely to be serializing fonts to JSON or whatever. (I've tried it, it doesn't work...) So perhaps a custom ser/de would even be simpler.

    Would be interested to hear opinions on this, particularly from @cmyr @raphlinus.

    opened by simoncozens 5
  • Moves private helper types into deserialize impl

    Moves private helper types into deserialize impl

    Feel free to close if this doesn't make sense, but I find it helpful when doing this to just declare the types in the method where they're used.

    opened by cmyr 4
  • fontcrunch: Replace Rc<Option> with Option<Rc>

    fontcrunch: Replace Rc

    This lets us avoid an allocation in the None case. Profiling allocations on a sample font, this cuts the total number of allocations by ~60%.

    opened by cmyr 4
  • Change Win EncodingID to 1

    Change Win EncodingID to 1

    This matches fontmake and it's also recommended in the ms spec

    When building a Unicode font for Windows, the platform ID should be 3 and the encoding ID should be 1, and the referenced string data must be encoded in UTF-16BE.


    opened by m4rc1e 4
  • Add ttf-add-smooth-gasp

    Add ttf-add-smooth-gasp

    At GF, we like to release unhinted fonts which have their gasp tables set to smooth for all sizes.

    Keep this open since our FB check seems a bit strange. The check wants a single range with all the flags enabled which imo feel wrong, or there's some magic going on which is undocumented. I'm just confirming why we made this decision with Felipe.

    I'd maybe keep this open for a week or so. I only started playing with Rust yesterday so most likely this is shockingly bad.

    opened by m4rc1e 3
  • Fix installing dependency otf-fea-rs

    Fix installing dependency otf-fea-rs

    otf-fea-rs doesn't contain a master branch. Its default branch is "trunk".

    opened by m4rc1e 2
  • Calculate unicode ranges

    Calculate unicode ranges

    Super wip. My implementation is loosely based on https://github.com/fonttools/fonttools/blob/main/Lib/fontTools/ttLib/tables/O_S_2f_2.py. The fonttools version uses python's built in bisect module in order to achieve a good run time. I don't think Rust has this so I've opted roll my own custom binary search instead.

    Note this is still super wip. Before I plumb it together, I'll ask for a review. It should be ready for a first look tomorrow.

    opened by m4rc1e 2
  • ttf-rename-glyphs turns space to 0020

    ttf-rename-glyphs turns space to 0020

    (and fontbakery doesn't like that)

    opened by simoncozens 0
  • Support floating-point values in designspace documents

    Support floating-point values in designspace documents

    The spec just calls them "numbers" which isn't helpful, but apparently floats are allowed for axis min, max, default, and locations.

    opened by simoncozens 3
  • Optimize gvar tables

    Optimize gvar tables

    • [ ] Implement shared point computation
    • [x] Implement private point (sub-range) support
    • [x] Implement IUP optimisation
    opened by simoncozens 0
  • GSUB and GPOS tables

    GSUB and GPOS tables

    We need to serialize and deserialise all of these, and add a feature file parser.

    opened by simoncozens 1
  • Correct OS/2 dummy fields

    Correct OS/2 dummy fields

    fsSelection, Unicode code ranges and code page values in build_os2 are bogus. They need computing properly.

    good first issue 
    opened by simoncozens 0
  • MVAR/HVAR tables

    MVAR/HVAR tables

    • [ ] Implement and test serialization/deserialization of MVAR/HVAR tables
    • [ ] Add ttf-gvar-to-hvar utility
    opened by simoncozens 0
  • > #![allow(non_snake_case, non_camel_case_types)]

    > #![allow(non_snake_case, non_camel_case_types)]

    nooooooooooooooooooooooooooooo :sob:

    opened by madig 2
Simon Cozens
Simon Cozens
An XPath library in Rust

SXD-XPath An XML XPath library in Rust. Overview The project is broken into two crates: document - Basic DOM manipulation and reading/writing XML from

Jake Goulding 97 Jul 10, 2021
An XML library in Rust

xml-rs, an XML library for Rust Documentation xml-rs is an XML library for Rust programming language. It is heavily inspired by Java Streaming API for

Vladimir Matveev 358 Sep 7, 2021
Yet Another Serializer/Deserializer

yaserde   Yet Another Serializer/Deserializer specialized for XML Goal This library will support XML de/ser-ializing with all specific features. Suppo

null 100 Sep 3, 2021
Rust high performance xml reader and writer

quick-xml High performance xml pull reader/writer. The reader: is almost zero-copy (use of Cow whenever possible) is easy on memory allocation (the AP

Johann Tuffe 584 Sep 13, 2021
A XML parser written in Rust

RustyXML Documentation RustyXML is a namespace aware XML parser written in Rust. Right now it provides a basic SAX-like API, and an ElementBuilder bas

null 86 Sep 3, 2021