Open andreinitescu opened 3 years ago
I'm trying to get the unicode for a glyph.
In the example below, I'm looking to get the F000 value for the glyph with index 66:
Per my understanding, in fontkit "unicode code point" refers to the "index" in the image above. How can I get the unicode (F000) value?
Having the same issue @andreinitescu did you find a workaround for this?
@andreinitescu is there a specific public release for that font that you can link to, with some minimal code that does everything to reproduce the problem you had?
Here a reduced test case
@Pomax I cannot remember exactly which font was it, but I think it was Font Awesome (glass-martini glyph in the screenshot).
@guidoferreyra Sorry, I cannot remember, it's been a year.
@guidoferreyra Interestingly, your test case uses a version of Roboto that has no official release. Turning that zip file into a post:
const fontkit = require('fontkit');
const font = fontkit.openSync('Roboto-Thin.ttf');
for (let i = 0; i < font.numGlyphs; i++) {
const glyph = font.getGlyph(i);
console.log(glyph.id, glyph.name, glyph.codePoints)
}
Does this also happen for v2.138? If so, can we turn that for loop into a specific single character for which this is known to go wrong, rather than a few tens of thousands of console logs? =)
I used Roboto just because was the first font that appeared on Google Fonts, but it’s happening with any font.
Just tested and this is happening with v2.138, v2.0 and v1.9
I dig into the source code, the way getGlyph()
is written is never meant to return codePoints
, and it takes the second parameters and use that as codePoints
, since the usage getGlyph(glyphId)
omit the second parameter, it default the codePoints
to an empty array []
and that is being used to construct the Glyph object and being returned.
When font.layout()
internally called getGlyph()
, the text string is converted to codePoints
and pass into the getGlyph()
as the second parameter and that get added to the Glyph
object inside GlyphRun
, so these Glyph has codePoints.
I find this API design confusing, making the Glyph object that get returned very unreliable.
Related source code snippets:
getGlyph pass the params into this private function _getBaseGlyph
_getBaseGlyph(glyph, characters = []) {
if (!this._glyphs[glyph]) {
if (this.directory.tables.glyf) {
this._glyphs[glyph] = new TTFGlyph(glyph, characters, this);
} else if (this.directory.tables['CFF '] || this.directory.tables.CFF2) {
this._glyphs[glyph] = new CFFGlyph(glyph, characters, this);
}
}
return this._glyphs[glyph] || null;
}
new TTFGlyph
( and other similar new Glyph
for different format) all calls this constructor:
export default class Glyph {
constructor(id, codePoints, font) {
/**
* The glyph id in the font
* @type {number}
*/
this.id = id;
/**
* An array of unicode code points that are represented by this glyph.
* There can be multiple code points in the case of ligatures and other glyphs
* that represent multiple visual characters.
* @type {number[]}
*/
this.codePoints = codePoints;
this._font = font;
// TODO: get this info from GDEF if available
this.isMark = this.codePoints.length > 0 && this.codePoints.every(isMark);
this.isLigature = this.codePoints.length > 1;
}
...
is it too nasty to use font._cmapProcessor.codePointsForGlyph(id);
on the glyph constructor? It works for me.
export default class Glyph {
constructor(id, codePoints, font) {
/**
* The glyph id in the font
* @type {number}
*/
this.id = id;
/**
* An array of unicode code points that are represented by this glyph.
* There can be multiple code points in the case of ligatures and other glyphs
* that represent multiple visual characters.
* @type {number[]}
*/
if (codePoints.length == 0) {
this.codePoints = font._cmapProcessor.codePointsForGlyph(id);
} else {
this.codePoints = codePoints;
}
this._font = font;
// TODO: get this info from GDEF if available
this.isMark = this.codePoints.length > 0 && this.codePoints.every(isMark);
this.isLigature = this.codePoints.length > 1;
}
Any idea why
getGlyph(gid)
returns a Glyph withcodePoints
as an empty array?I'm sure the gid I pass is correct.