Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

variable fonts: VariationManager set axes values for rendering #722

Closed
herrstrietzel opened this issue Jun 2, 2024 · 12 comments
Closed

Comments

@herrstrietzel
Copy link

Obviously, opentype.js variable font features are still quite new - so thanks a lot for these exiting new features!
From the current readme we should be able to set variable font axis values for rendering - which doesn't work.

Expected Behavior

The parsed font object should return some info when logging
Font.variation.activateDefaultVariation() or
Font.variation.getDefaultCoordinates()

Current Behavior

Cannot read properties of undefined (reading 'getInstance')
So we can't access or control any variation properties

Steps to Reproduce (for bugs)

I'm using version 1.3.4
here is a simple codepen example:

I can successfully parse and render the font - the Open Sans ttf version.
I can also retrieve the fvar table to retrieve the available axes as well as min, default, max values (returning the expected values).

But I can't access the VariationManager API methods such as Font.variation.getDefaultCoordinates()

(async () => {
    /**
     * load variable font version of open sans
     * axes: 
     * 'wght', minValue: 300, defaultValue: 400, maxValue: 800
     * 'wdth', minValue: 75, defaultValue: 100, maxValue: 100
     */
    let fonturl = 'https://fonts.gstatic.com/s/opensans/v40/mem8YaGs126MiZpBA-U1UpcaXcl0Aw.ttf';
    let buffer = await (await fetch(fonturl)).arrayBuffer();
    
    // parse
    let font = opentype.parse(buffer);
    console.log(font);
    
    try{
      let variation = font.variation.getInstance(1)
      console.log(variation);
    }catch{
      console.log('no variation data');
    }

    //render
    let text = 'Hamburgefons';
    let fontSize = 72;
    let x=0;
    let y=fontSize
    let path = font.getPath(text, x, y, fontSize);
    //console.log(path)
    let pathEl = path.toDOMElement();
    
    svg.append(pathEl)
    
  })()

Probably I'm just too stupid or the new API is still flux.
However, the readme could be more clear how we can set axes values for rendering
I think the API could take inspiration from fontkit as explained here "Getting outlines of variable font?

It is not clear if we need an abstraction for the axis values

font.variation.getTransform(2, { test: 0.42 });

Does this mean, we need to translate axis values to a range between 0-1 like so

font.variation.getTransform( glyphIndex, { wght: 0 });

Where 0 would translate to the min value in case of Open Sans '300'?

@ILOVEPIE
Copy link
Contributor

ILOVEPIE commented Jun 2, 2024

1.3.4 is outdated and does not support variable fonts. Use 2.0.0 instead from the master branch. We will be updating the version on npm when 2.0.0 is finished.

@herrstrietzel
Copy link
Author

Thank you so much for your quick response!
Compiling version 2.0.0 does the trick – it's awesome!

However, it seems like the SVG conversion has a minor bug.
It doesn't flip the traditional Cartesian y-axis from "bottom-to-top" (native font design) to "top-to-bottom" when applying svg conversions:

See updated codepen example (same URL - but updated)

(async () => {
    /**
     * load variable font version of open sans
     * axes: 
     * 'wght', minValue: 300, defaultValue: 400, maxValue: 800
     * 'wdth', minValue: 75, defaultValue: 100, maxValue: 100
     */
    let fonturl = 'https://fonts.gstatic.com/s/opensans/v40/mem8YaGs126MiZpBA-U1UpcaXcl0Aw.ttf';
    let buffer = await (await fetch(fonturl)).arrayBuffer();
    
    // parse
    let font = opentype.parse(buffer);
    
    /**
    * AWESOME!!!
    * should be the first paragraph in the readme
    */
    font.variation.set({wght: 800, wdth: 75})


    //render
    let text = 'Hamburgefons';
    let fontSize = 72;
    let x=0;
    let y=fontSize
    let path = font.getPath(text, x, y, fontSize);
    //console.log(path)
    let pathEl = path.toDOMElement();
    
    svg.append(pathEl)
    
  })()

Works beautifully (except this tiny flipping error).
But imho you should definitely emphasize the axis control in the readme.

    font.variation.set({wght: 800, wdth: 75})

@ILOVEPIE
Copy link
Contributor

ILOVEPIE commented Jun 2, 2024

Thank you so much for your quick response!
Compiling version 2.0.0 does the trick – it's awesome!

However, it seems like the SVG conversion has a minor bug.
It doesn't flip the traditional Cartesian y-axis from "bottom-to-top" (native font design) to "top-to-bottom" when applying svg conversions:

See updated codepen example (same URL - but updated)

(async () => {
    /**
     * load variable font version of open sans
     * axes: 
     * 'wght', minValue: 300, defaultValue: 400, maxValue: 800
     * 'wdth', minValue: 75, defaultValue: 100, maxValue: 100
     */
    let fonturl = 'https://fonts.gstatic.com/s/opensans/v40/mem8YaGs126MiZpBA-U1UpcaXcl0Aw.ttf';
    let buffer = await (await fetch(fonturl)).arrayBuffer();
    
    // parse
    let font = opentype.parse(buffer);
    
    /**
    * AWESOME!!!
    * should be the first paragraph in the readme
    */
    font.variation.set({wght: 800, wdth: 75})


    //render
    let text = 'Hamburgefons';
    let fontSize = 72;
    let x=0;
    let y=fontSize
    let path = font.getPath(text, x, y, fontSize);
    //console.log(path)
    let pathEl = path.toDOMElement();
    
    svg.append(pathEl)
    
  })()

Works beautifully (except this tiny flipping error).
But imho you should definitely emphasize the axis control in the readme.

    font.variation.set({wght: 800, wdth: 75})

Have you tried setting the variation in the options variable when you create the path? That might work better. And that way you can have the variation set for each individual time you get a path instead of on the path. Also, just a heads up, Google does some screwy things with Google fonts, so it's not generally a good idea to use fonts from there and to use the original source of the font, because oftentimes Google modifies the font when they upload it.

@ILOVEPIE
Copy link
Contributor

ILOVEPIE commented Jun 2, 2024

If I remember correctly Font.variation.set() is only supposed to be used to set the default font variation. But I may be wrong as I don't have the documentation or the code in front of me.

@herrstrietzel
Copy link
Author

It also occurs without any specified axis info.
I'm pretty sure this flipping is caused by the waaaaaaaaaay more complex translation from delta based glyf data to SVG than it was before - in the static font days.
Once again I seriously consider this flipped rendering a minor bug. It's awesome to retrieve a axis based rendering in opentype.js.
I'll also have a look at it.

@Connum
Copy link
Contributor

Connum commented Jun 2, 2024

I'm travelling right now so can't really look into this right now, but does toDOMElement({ flipY: true }) not work?

@herrstrietzel
Copy link
Author

Thanks for your help. I think I've found the problem.
In fact the y-Axis flip is done twice

    let path = font.getPath(text, x, y, fontSize);
   // already flipped
    let d0 = path.commands.map(com => { return Object.values(com).join(' ') }).join(' ')
    console.log( d0);

   // flipped again
    let d = path.toPathData();
    console.log(d);

So I guess the y transformation can either be removed from Glyph.prototype.getPath or Path.toPathData()

See new pen

@Connum
Copy link
Contributor

Connum commented Jun 2, 2024

Just use path.toPathData({ flipY: true })

@herrstrietzel
Copy link
Author

I would actually need to use path.toPathData({ flipY: false}) to get the typical SVG coordinate adjustment.
This issue didn't occur in previous versions so I guess the default behaviour has changed to the overhauled coordinate calculations.
BTW. I could also reproduce this error with static ttf fonts.
But it's not a huge deal. Thanks for the great new VF capabilities - that's a game changer!

@ILOVEPIE
Copy link
Contributor

ILOVEPIE commented Jun 2, 2024

I would actually need to use path.toPathData({ flipY: false}) to get the typical SVG coordinate adjustment.
This issue didn't occur in previous versions so I guess the default behaviour has changed to the overhauled coordinate calculations.
BTW. I could also reproduce this error with static ttf fonts.
But it's not a huge deal. Thanks for the great new VF capabilities - that's a game changer!

If that's the case, it's a good thing we found that before releasing 2.0.0

@herrstrietzel
Copy link
Author

@ILOVEPIE: thanks again for your support! Since my initial question was solved you can close this report.
I will file a separate issue report specific to the y-axis flipping default-behaviour for further investigations.
@Connum: Thanks for your help as well - enjoy your journey!

@Connum
Copy link
Contributor

Connum commented Jun 3, 2024

Thanks!

@Connum Connum closed this as completed Jun 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants