Giter Club home page Giter Club logo

Comments (9)

RazrFalcon avatar RazrFalcon commented on June 12, 2024
  1. OwnedFace and SelfRefVecFace are part of the owned_ttf_parser crate, not this crate.
  2. Table data ranges in the original file are not preserved. The closest thing is RawFace::table_records which is currently private. Why would you even what this? Maybe you're looking for Face::table_data()?
  3. Do you want to (de)serde the whole font? It would not be possible, because ttf-parser doesn't parse anything except the core layout by default, so there is nothing to serialize. Also, a json representation of a font could easily reach hundreds of megabytes.

from ttf-parser.

wdanilo avatar wdanilo commented on June 12, 2024

@RazrFalcon thank you so much for the answers! As all of your questions are connected, let me reply not in points, starting with a short description of the use case I have here.

Use case

From legal reasons, we cannot ship the whole font representation in our app. So what I want to do is to parse the font, generate SDF representation of chosen glyphs, remove the glyph info from the font binary data, and serialise to disk the changed binary font data and the SDF glyph atlas (this will be our custom "font file" that we will be shipping with the app). This way, we will have a binary data containing helper info (such as the kerning table) + glyph atlases but without exact glyph shapes (with zeroed values in the glyf::Table::data).

OwnedFace issue (not really important here)

Right now, I'm converting the Vec<u8> to OwnedFace with OwnedFace::from_vec, and unfortunately, I can't access it anymore, as it's kept as private field, so I need to keep clone of the original Vec<u8> in order to later modify it. I understand that this is something I should report on the other repo.

This library issues

Regarding Table data ranges in the original file are not preserved - this is surprising to me. I was sure that all the Tables are just slices over the original &[u8], which means that I could use pointer arithmetics to understand where the glyf::Table starts and ends in the original Vec<u8>. I've created a code to remove this data and it seems to work:

    pub fn remove_glyph_data(&mut self) {
        mem::take(&mut self.msdf_font);
        let data_slice = &self.data[..]; // This is original `Vec<u8>`.
        if let Ok(font_face) = ttf::RawFace::from_slice(data_slice, FONT_FACE_NUMBER) {
            if let Some(glyph_table) = font_face.table(ttf::Tag::from_bytes(b"glyf")) {
                let glyph_table_ptr = glyph_table.as_ptr();
                let data_ptr = data_slice.as_ptr();
                // Safety: This is safe, as both pointers refer to the same slice.
                let start_index = unsafe { glyph_table_ptr.offset_from(data_ptr) };
                for offset in 0..glyph_table.len() {
                    self.data[start_index as usize + offset] = 0;
                }
            }
        }
        if let Ok(font_face) = ttf::OwnedFace::from_vec(self.data.clone(), FONT_FACE_NUMBER) {
            self.font_face = font_face;
        }
    }

What I don't like in the code above is the operation duplication. I already have self.font_face : OwnedFace, so I could access its internal Vec<u8> and I could access the glyf::Table information there without the need of constructing RawFace. Does it make sense to you?

from ttf-parser.

RazrFalcon avatar RazrFalcon commented on June 12, 2024

Ok, I understand the idea.

  1. I don't think that zeroing glyf table is enough to avoid licensing issues. I think OpenType layout tables (GDEF, GSUB, GPOS) are more valuable. But IANAL.
  2. Do you aware that glyf is not the only way to store outlines?
  3. Do you aware that modern fonts do no use kerning?
  4. You might be interested in using fonttools. You can use the ttx utility to convert a font into XML, edit it, and convert back to ttf. Which is still illegal.
  5. Yes, you can use pointer arithmetic to get offsets, but we do not provide any kind of API for that. It's a very rare use case.
  6. Also, technically, by zeroing glyf you're making the font invalid, because you also have to update table's CRC and checksumAdjustment in head table. But many TrueType parsers, just like ttf-parser, simply ignore CRC.

from ttf-parser.

wdanilo avatar wdanilo commented on June 12, 2024

@RazrFalcon thanks so much for super fast answer!

  1. Let me explain here an important thing – we are not trying to do anything illegal! We got an official information from the font store that if we will be able to display in our app glyphs but in such a way that the original fonts will not be extractable from the app, we can use a more liberal licensing. The whole thing is super strange, as they provide a lot of licensing options, including licensing for cloud-usage (which we are paying for), for phone-usage, even for watch-device-like usage, but there are no licenses available for standard desktop app installations. You can buy licenses of this font for "developers" that are using the font to build apps, but if the original font will be extractable from the app, then every user is considered a "developer". If it's not, then we can simply use cloud license + license for our developers. Anyway, what we are doing is not our "invention", we are following what our font provider told us to do.

  2. I was not aware of it! Thank you so much for mentioning it! Would then zeroing GLYF, GDEF, GSUB, GPOS tables be enough to remove the info about glyph shapes?

  3. I was not aware either. What is interesting is that so far we've been using DejavuSansMono in some parts of our app and it uses kerning. Using the rare opportunity that I can ask someone knowing much more about fonts than me, would you be so nice and tell me if there are any other tables that we should consider when layouting glyphs on the screen, assuming that we want to support English language only for now? (We have custom WebGL font renderer).

  4. Thanks for mentioning it! Regarding legal issues, I hope I covered them in point 1, however, I'm still very thankful that you take care of that and you guide me not to do something stupid. I really appreciate it. Regarding doing that with font tools (via XML) versus the method that I described in my previous post - would that have any advantages? Zeroing (or removing) the data as in my code above seems like a good automated solution to me.

  5. My only question here is if it would be possible to have API to gett reference to glyf::Table::data and to Face::raw_face. If these references (immutable) could be exposed, a lot of my code will simplify and I believe that it would not introduce any downsides for other users. What do you think of that?

  6. Again, thank you so much for mentioning it. We will be parsing the updated binary format only with ttf-parser, so it will work in our case then.

from ttf-parser.

RazrFalcon avatar RazrFalcon commented on June 12, 2024
  1. Good. I'm glad that this part is covered.
  2. Well... we're do I even begin. We have glyf, glyf + gvar (Apple variable fonts), CFF (OpenType/Adobe fonts) and CFF2 (OpenType variable fonts). Those tables contain font outlines. ttf-parser support all of them. Not to mention that there are also bitmap and SVG font tables out there.
  3. As for GDEF, GSUB, GPOS, they contain glyphs layout metadata. Specifically complex substitution and positioning info (think Arabic scripts). They are required to do proper text shaping. Not sure what you app does right now. You might be interested in rustybuzz. But for Latin-only script you should be fine without it.
  4. Well, fonttools provides proper subsetting, meaning you can use it to remove unused glyphs from the font. Basically a font optimization pass.
  5. I think it's a very specific use case that can easily be implemented on the caller side.

You can also try ttf-explorer. This would help understanding the font format layout better.

from ttf-parser.

wdanilo avatar wdanilo commented on June 12, 2024

@RazrFalcon Again, thanks for fast reply!

  1. :)
  2. Thank you so much for this info!
  3. Gotcha! :) We were considering rustybuzz, but for now it seems like an overkill for our use case. Thanks for mentioning it!
  4. Make sense, thanks!
  5. Without these changes I am required to do parsing 2 times (constructing both OnwedFace and RawFace). It is not a huge overhead, however, it will be just nicer to be able to access these fields. If I understand correctly your reply, you are not willing to expose this information in the API, am I correct? If so, then yes, I would just keep parsing the font data twice – I was just hoping that exposing these accessors will not be a bigger issue, as it does not negatively affect other users and might actually enable them to implement some more exotic use cases (as this one).

Thank you once again for all replies and your help!

from ttf-parser.

RazrFalcon avatar RazrFalcon commented on June 12, 2024

Glad to hear.

Ok, I will think about exposing Face::raw_face.

from ttf-parser.

wdanilo avatar wdanilo commented on June 12, 2024

I would be really thankful for doing it!! ❤️

from ttf-parser.

RazrFalcon avatar RazrFalcon commented on June 12, 2024

You can access this data using:

if let Some(record) = face.raw_face().table_records.into_iter().find(|r| r.tag == Tag::from_bytes(b"glyf")) {
    println!("{:?}", record); // TableRecord { tag: Tag(glyf), check_sum: 3391114546, offset: 28780, length: 105582 }
}

from ttf-parser.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.