GithubHelp home page GithubHelp logo

fontkit's Introduction

fontkit

Fontkit is an advanced font engine for Node and the browser, used by PDFKit. It supports many font formats, advanced glyph substitution and layout features, glyph path extraction, color emoji glyphs, font subsetting, and more.

Features

  • Supports TrueType (.ttf), OpenType (.otf), WOFF, WOFF2, TrueType Collection (.ttc), and Datafork TrueType (.dfont) font files
  • Supports mapping characters to glyphs, including support for ligatures and other advanced substitutions (see below)
  • Supports reading glyph metrics and laying out glyphs, including support for kerning and other advanced layout features (see below)
  • Advanced OpenType features including glyph substitution (GSUB) and positioning (GPOS)
  • Apple Advanced Typography (AAT) glyph substitution features (morx table)
  • Support for getting glyph vector paths and converting them to SVG paths, or rendering them to a graphics context
  • Supports TrueType (glyf) and PostScript (CFF) outlines
  • Support for color glyphs (e.g. emoji), including Apple’s SBIX table, and Microsoft’s COLR table
  • Support for AAT variation glyphs, allowing for nearly infinite design control over weight, width, and other axes.
  • Font subsetting support - create a new font including only the specified glyphs

Installation

npm install fontkit

Example

var fontkit = require('fontkit');

// open a font synchronously
var font = fontkit.openSync('font.ttf');

// layout a string, using default shaping features.
// returns a GlyphRun, describing glyphs and positions.
var run = font.layout('hello world!');

// get an SVG path for a glyph
var svg = run.glyphs[0].path.toSVG();

// create a font subset
var subset = font.createSubset();
run.glyphs.forEach(function(glyph) {
  subset.includeGlyph(glyph);
});

let buffer = subset.encode();

API

fontkit.open(filename, postscriptName = null)

Opens a font file asynchronously, and returns a Promise with a font object. For collection fonts (such as TrueType collection files), you can pass a postscriptName to get that font out of the collection instead of a collection object.

fontkit.openSync(filename, postscriptName = null)

Opens a font file synchronously, and returns a font object. For collection fonts (such as TrueType collection files), you can pass a postscriptName to get that font out of the collection instead of a collection object.

fontkit.create(buffer, postscriptName = null)

Returns a font object for the given buffer. For collection fonts (such as TrueType collection files), you can pass a postscriptName to get that font out of the collection instead of a collection object.

Font objects

There are several different types of font objects that are returned by fontkit depending on the font format. They all inherit from the TTFFont class and have the same public API, described below.

Metadata properties

The following properties are strings (or null if the font does not contain strings for them) describing the font, as specified by the font creator.

  • postscriptName
  • fullName
  • familyName
  • subfamilyName
  • copyright
  • version

Metrics

The following properties describe the general metrics of the font. See here for a good overview of how all of these properties relate to one another.

  • unitsPerEm - the size of the font’s internal coordinate grid
  • ascent - the font’s ascender
  • descent - the font’s descender
  • lineGap - the amount of space that should be included between lines
  • underlinePosition - the offset from the normal underline position that should be used
  • underlineThickness - the weight of the underline that should be used
  • italicAngle - if this is an italic font, the angle the cursor should be drawn at to match the font design
  • capHeight - the height of capital letters above the baseline. See here for more details.
  • xHeight- the height of lower case letters. See here for more details.
  • bbox - the font’s bounding box, i.e. the box that encloses all glyphs in the font

Other properties

  • numGlyphs - the number of glyphs in the font
  • characterSet - an array of all of the unicode code points supported by the font
  • availableFeatures - an array of all OpenType feature tags (or mapped AAT tags) supported by the font (see below for a description of this)

Character to glyph mapping

Fontkit includes several methods for character to glyph mapping, including support for advanced OpenType and AAT substitutions.

font.glyphForCodePoint(codePoint)

Maps a single unicode code point (number) to a Glyph object. Does not perform any advanced substitutions (there is no context to do so).

font.hasGlyphForCodePoint(codePoint)

Returns whether there is glyph in the font for the given unicode code point.

font.glyphsForString(string)

This method returns an array of Glyph objects for the given string. This is only a one-to-one mapping from characters to glyphs. For most uses, you should use font.layout (described below), which provides a much more advanced mapping supporting AAT and OpenType shaping.

Glyph metrics and layout

Fontkit includes several methods for accessing glyph metrics and performing layout, including support for kerning and other advanced OpenType positioning adjustments.

font.widthOfGlyph(glyph_id)

Returns the advance width (described above) for a single glyph id.

font.layout(string, features = [] | {})

This method returns a GlyphRun object, which includes an array of Glyphs and GlyphPositions for the given string. Glyph objects are described below. GlyphPosition objects include 4 properties: xAdvance, yAdvance, xOffset, and yOffset.

The features parameter is either an array of OpenType feature tags to be applied in addition to the default set, or an object mapping OpenType features to a boolean enabling or disabling each. If this is an AAT font, the OpenType feature tags are mapped to AAT features.

Variation fonts

Fontkit has support for AAT variation fonts, where glyphs can adjust their shape according to user defined settings along various axes including weight, width, and slant. Font designers specify the minimum, default, and maximum values for each axis they support, and allow the user fine grained control over the rendered text.

font.variationAxes

Returns an object describing the available variation axes. Keys are 4 letter axis tags, and values include name, min, default, and max properties for the axis.

font.namedVariations

The font designer may have picked out some variations that they think look particularly good, for example a light, regular, and bold weight which would traditionally be separate fonts. This property returns an object describing these named variation instances that the designer has specified. Keys are variation names, and values are objects with axis settings.

font.getVariation(variation)

Returns a new font object representing this variation, from which you can get glyphs and perform layout as normal. The variation parameter can either be a variation settings object or a string variation name. Variation settings objects have axis names as keys, and numbers as values (should be in the range specified by font.variationAxes).

Other methods

font.getGlyph(glyph_id, codePoints = [])

Returns a glyph object for the given glyph id. You can pass the array of code points this glyph represents for your use later, and it will be stored in the glyph object.

font.createSubset()

Returns a Subset object for this font, described below.

Font Collection objects

For font collection files that contain multiple fonts in a single file, such as TrueType Collection (.ttc) and Datafork TrueType (.dfont) files, a font collection object can be returned by Fontkit.

collection.getFont(postscriptName)

Gets a font from the collection by its postscript name. Returns a Font object, described above.

collection.fonts

This property is a lazily-loaded array of all of the fonts in the collection.

Glyph objects

Glyph objects represent a glyph in the font. They have various properties for accessing metrics and the actual vector path the glyph represents, and methods for rendering the glyph to a graphics context.

You do not create glyph objects directly. They are created by various methods on the font object, described above. There are several subclasses of the base Glyph class internally that may be returned depending on the font format, but they all include the following API.

Properties

  • id - the glyph id in the font
  • name - the glyph name in the font
  • codePoints - 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.
  • path - a vector Path object representing the glyph
  • bbox - the glyph’s bounding box, i.e. the rectangle that encloses the glyph outline as tightly as possible.
  • cbox - the glyph’s control box. This is often the same as the bounding box, but is faster to compute. Because of the way bezier curves are defined, some of the control points can be outside of the bounding box. Where bbox takes this into account, cbox does not. Thus, cbox is less accurate, but faster to compute. See here for a more detailed description.
  • advanceWidth - the glyph’s advance width.

glyph.render(ctx, size)

Renders the glyph to the given graphics context, at the specified font size.

Color glyphs (e.g. emoji)

Fontkit has support for several different color emoji font formats. Currently, these include Apple’s SBIX table (as used by the “Apple Color Emoji” font), and Microsoft’s COLR table (supported by Windows 8.1). Here is an overview of the various color font formats out there.

glyph.getImageForSize(size)

For SBIX glyphs, which are bitmap based, this returns an object containing some properties about the image, along with the image data itself (usually PNG).

glyph.layers

For COLR glyphs, which are vector based, this returns an array of objects representing the glyphs and colors for each layer in render order.

Path objects

Path objects are returned by glyphs and represent the actual vector outlines for each glyph in the font. Paths can be converted to SVG path data strings, or to functions that can be applied to render the path to a graphics context.

path.moveTo(x, y)

Moves the virtual pen to the given x, y coordinates.

path.lineTo(x, y)

Adds a line to the path from the current point to the given x, y coordinates.

path.quadraticCurveTo(cpx, cpy, x, y)

Adds a quadratic curve to the path from the current point to the given x, y coordinates using cpx, cpy as a control point.

path.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

Adds a bezier curve to the path from the current point to the given x, y coordinates using cp1x, cp1y and cp2x, cp2y as control points.

path.closePath()

Closes the current sub-path by drawing a straight line back to the starting point.

path.toFunction()

Compiles the path to a JavaScript function that can be applied with a graphics context in order to render the path.

path.toSVG()

Converts the path to an SVG path data string.

path.bbox

This property represents the path’s bounding box, i.e. the smallest rectangle that contains the entire path shape. This is the exact bounding box, taking into account control points that may be outside the visible shape.

path.cbox

This property represents the path’s control box. It is like the bounding box, but it includes all points of the path, including control points of bezier segments. It is much faster to compute than the real bounding box, but less accurate if there are control points outside of the visible shape.

Subsets

Fontkit can perform font subsetting, i.e. the process of creating a new font from an existing font where only the specified glyphs are included. This is useful to reduce the size of large fonts, such as in PDF generation or for web use.

Currently, subsets produce minimal fonts designed for PDF embedding that may not work as standalone files. They have no cmap tables and other essential tables for standalone use. This limitation will be removed in the future.

You create a Subset object by calling font.createSubset(), described above. The API on Subset objects is as follows.

subset.includeGlyph(glyph)

Includes the given glyph object or glyph ID in the subset.

subset.encode()

Returns a Uint8Array containing the encoded font file.

License

MIT

fontkit's People

Contributors

achrist avatar adrift2000 avatar andreiaugustin avatar anthonmanix avatar blikblum avatar canda avatar connum avatar defue avatar dependabot[bot] avatar devongovett avatar ebraminio avatar felipesanches avatar fstrube avatar hauswirth avatar issacgerges avatar kennethormandy avatar khaledhosny avatar kierenj avatar liborm85 avatar luanpotter avatar musculman avatar pomax avatar scottrippey avatar sohobloo avatar toastal avatar tomashanacek avatar wxmahen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fontkit's Issues

How to catch errors like - Failed to deserialize table, cannot read property records...

I'm attempting to pull local fonts into an Electron app. All is working except, obviously, some of the fonts are not serializable and also seeing a cannot read property records of undefined.

Serialize errors from inspector look like:

Failed to decode downloaded font: file:///Library/Fonts/BigCaslon.ttf
OTS parsing error: cmap: failed to serialize table
Failed to decode downloaded font: file:///Library/Fonts/HeadlineA.ttf
OTS parsing error: OS/2: missing required table
Failed to decode downloaded font: file:///Library/Fonts/Diwan%20Thuluth.ttf
OTS parsing error: cmap: Failed to parse format 4 cmap subtable 0
Failed to decode downloaded font: file:///Library/Fonts/Gungseouche.ttf
OTS parsing error: OS/2: missing required table
Failed to decode downloaded font: file:///Library/Fonts/AppleGothic.ttf
OTS parsing error: OS/2: missing required table
Failed to decode downloaded font: file:///Library/Fonts/AppleMyungjo.ttf
OTS parsing error: OS/2: missing required table

undefined error looks like (I replaced the full path with 'localPath' before pasting here):

TTFFont.js:104 Uncaught (in promise) TypeError: Cannot read property 'records' of undefined
    at TTFFont.getName (localPath/node_modules/fontkit/index.js:12642:29)
    at TTFFont.get (localPath/node_modules/fontkit/index.js:12902:19)

I looked and it seems there is a font.fullName property but not a font.name property, so it seems to be assuming that if there's a fullName there has to be a .name property and I guess that's not guaranteed. Almost all the fonts are loading and working correctly. It's just the ones above that aren't.

I was getting an error when a fullName property was undefined but I added a check for that and it fixed that issue....

if( font.fullName === undefined ) return;

I tried adding...

  if( font.name === undefined ) return;

... but it doesn't seem to keep it from proceeding.

This is an app that could be run on several different machines so font sets will vary. I'd like a more elegant way to allow these to fail and then just jump out of using that particular font file. Just fyi, I'm only processing otf, ttf, woff and woff2 files. Everything else gets removed from the array.

Bug in OTProcessor.js - method getClassID

Commit 554a005 introduced a bug that sometimes causes crash - it may be return undefined.

For example:
This lines: https://github.com/devongovett/fontkit/blob/08171fe567b4922325bcd5a268e238501624b890/src/opentype/OTProcessor.js#L237-L240
When glyph is 3 and classDef.startGlyph is 4. Variable i will be -1.
Condition will be valid and will be returned index -1 from array which will undefined. And this causes an error in the other methods.
Probably there should be something like: if (i > -1 && i < classDef.classValueArray.length) {

I do not know exactly how it should work, but condition for negative number i do not return true.

This bug causes crash in https://github.com/bpampuch/pdfmake when I use any font.

Encoding of font files

I noticed that the only way that fontkit seems to provide encoding capability is by creating a subset. The library API and the code implementation seem (at least at first glance) to be built around the idea that it will be mostly used for decoding font files, even though encoding files is made possible via the special case of subsets.

As I am not yet much familiar with the CoffeeScript language, it is not clear to me if I'm right about the above statement. Please correct me if I'm wrong.

I guess it would be good to make the API and implementation more symmetric in terms of read/write features. I'd like to suggest that we use this GitHub issue to map which features are still not implemented towards getting proper encoding of fontfiles in fontkit as well.

Here are the encoding routines that I think we're still missing:

  • glyph contours

4 person family groups not supported from Apple Color Emoji.ttf

let font = fontkit.openSync("/System/Library/Fonts/Apple Color Emoji.ttf");
let emojis = [ '👨‍👩‍👧‍👦','👨‍👩‍👦‍👦','👨‍👩‍👧‍👧', '👩‍👩‍👧‍👦','👩‍👩‍👦‍👦', '👩‍👩‍👧‍👧','👨‍👨‍👧‍👦', '👨‍👨‍👦‍👦','👨‍👨‍👧‍👧' ];

emojis.forEach(function(emoji){
    let layout;

    try {
        layout = font.layout(emoji);
    } catch (e) {
        console.error(`Error converting ${emoji} to image:`, e, e.stack);
    }
});

For each emoji produces

[TypeError: Cannot read property 'codePoints' of undefined] TypeError: Cannot read property 'codePoints' of undefined
    at AATMorxProcessor.processLigature (/Users/joshuabalfour/Projects/emoji-dating/misc/emojiXtract/node_modules/fontkit/src/aat/AATMorxProcessor.js:254:75)
    at /Users/joshuabalfour/Projects/emoji-dating/misc/emojiXtract/node_modules/fontkit/src/aat/AATMorxProcessor.js:4:59
    at AATStateMachine.process (/Users/joshuabalfour/Projects/emoji-dating/misc/emojiXtract/node_modules/fontkit/src/aat/AATStateMachine.js:55:11)
    at AATMorxProcessor.processSubtable (/Users/joshuabalfour/Projects/emoji-dating/misc/emojiXtract/node_modules/fontkit/src/aat/AATMorxProcessor.js:124:27)
    at AATMorxProcessor.process (/Users/joshuabalfour/Projects/emoji-dating/misc/emojiXtract/node_modules/fontkit/src/aat/AATMorxProcessor.js:81:18)
    at LayoutEngine.substitute (/Users/joshuabalfour/Projects/emoji-dating/misc/emojiXtract/node_modules/fontkit/src/layout/LayoutEngine.js:99:28)
    at LayoutEngine.layout (/Users/joshuabalfour/Projects/emoji-dating/misc/emojiXtract/node_modules/fontkit/src/layout/LayoutEngine.js:84:21)
    at TTFFont.layout (/Users/joshuabalfour/Projects/emoji-dating/misc/emojiXtract/node_modules/fontkit/src/TTFFont.js:218:33)
    at /Users/joshuabalfour/Projects/emoji-dating/misc/emojiXtract/Apple Color Emoji.js:35:17
    at Array.forEach (native)

Subset font seems to be broken

I made a subset font with the following script copied from README.md.
As a result, the font generated can not be used and previewed with any other applications including Apple's Font Book.

var fs = require('fs');
var fontkit = require('fontkit');

// open a font synchronously 
var font = fontkit.openSync('SourceSansPro-Regular.otf');

// layout a string, using default shaping features. 
// returns a GlyphRun, describing glyphs and positions. 
var run = font.layout('hellow world!');

// create a font subset 
var subset = font.createSubset();

run.glyphs.forEach(function(glyph) {
    subset.includeGlyph(glyph);
});

subset.encodeStream()
    .pipe(fs.createWriteStream('subset.otf'));

Bundling with webpack does not work

Hi,

running fontkit (and pdfkit) in an expressjs app works fine locally, but when I'm building it with webpack, it returns: Error: ENOENT: no such file or directory, open '/var/www/backend/data.trie'

This is my webpack config:

var Webpack = require('webpack');
var path = require('path');
var buildPath = path.resolve(__dirname, 'build');
var mainPath = path.resolve(__dirname, 'src', 'app.js');

var config = {

  target: 'node',
  entry: mainPath,
  output: {
    path: buildPath,
    filename: 'bundle.js'
  },
  node: {
    console: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    dns: 'empty',
    __dirname: false,
    __filename: false
  },
  module: {
    loaders: [
        {
            test: /\.js$/,
            loader: 'babel',
            query: {
                presets: ['es2015']
            }
        },
        {
            test: /\.json$/,
            loader: 'json'
        },
        ]
  }
};

module.exports = config;

When I copy the file data.trie from the node_modules folder to the same directory where I run the node app, it continues, but the same problem appears with use.trie then.
Any idea how to solve it?

Glyph mapping wrong

Hi there. I was trying out your fontkit, and all worked good for subsetting a font, except that the glyphs are being mapped to cidxxxx instead of their respective unicodes for me and thus not usable. Any clues?

Why is this project being developed? :)

I'm curious what the context of this project is; opentype.js seems to predate it and do most of what it does, so I wonder why you guys didn't contribute to that but start yet another sfnt js library :)

Loading some fonts produces error.

Hello!
We have a bunch of font which are producing error. Following:

/root/fontserver/node_modules/fontkit/node_modules/brotli/build/decode.js:1
function e(a){throw a;}var j=void 0,m=!0,p=null,s=!1,t,v={};v.readBinary=require("../src/read_memory");v||(v=eval("(function() { try { return Module || {} } catch(e) { return {} } })()"));var aa={},w;for(w in v)v.hasOwnProperty(w)&&(aa[w]=v[w]);var ba="object"===typeof process&&"function"===typeof require,ca="object"===typeof window,da="function"===typeof importScripts,ea=!ca&&!ba&&!da;
              ^

TypeError: Cannot read property '26979' of undefined
    at Object.r.Struct.string.r.Pointer.type (/root/fontserver/node_modules/fontkit/src/tables/name.js:14:40)
    at StringT.decode (/root/fontserver/node_modules/fontkit/node_modules/restructure/src/String.js:30:29)
    at /root/fontserver/node_modules/fontkit/node_modules/restructure/src/Pointer.js:69:30
    at Pointer.decode (/root/fontserver/node_modules/fontkit/node_modules/restructure/src/Pointer.js:79:16)
    at Struct._parseFields (/root/fontserver/node_modules/fontkit/node_modules/restructure/src/Struct.js:53:22)
    at Struct.decode (/root/fontserver/node_modules/fontkit/node_modules/restructure/src/Struct.js:18:12)
    at ArrayT.decode (/root/fontserver/node_modules/fontkit/node_modules/restructure/src/Array.js:49:30)
    at VersionedStruct.Struct._parseFields (/root/fontserver/node_modules/fontkit/node_modules/restructure/src/Struct.js:53:22)
    at VersionedStruct.decode (/root/fontserver/node_modules/fontkit/node_modules/restructure/src/VersionedStruct.js:42:12)
    at TTFFont._decodeTable (/root/fontserver/node_modules/fontkit/src/TTFFont.js:93:32)

That happens only while we trying to get font name (full or postscript).

Any fix on that?! Thanks!

Error: Unknown version 128

Code:

var fontkit = require('fontkit');
var font = fontkit.openSync('Verona-Xlight.ttf');
var run = font.layout('hello world!');

Output:

/home/defue/node_modules/brotli/build/decode.js:1
orts, require, module, __filename, __dirname) { function e(a){throw a;}var j=v
                                                                    ^
Error: Unknown version 128
    at VersionedStruct.decode (/home/defue/node_modules/restructure/src/VersionedStruct.js:37:15)
    at VersionedStruct.Struct._parseFields (/home/defue/node_modules/restructure/src/Struct.js:53:22)
    at VersionedStruct.decode (/home/defue/node_modules/restructure/src/VersionedStruct.js:42:12)
    at ArrayT.decode (/home/defue/node_modules/restructure/src/Array.js:49:30)
    at VersionedStruct.Struct._parseFields (/home/defue/node_modules/restructure/src/Struct.js:53:22)
    at VersionedStruct.decode (/home/defue/node_modules/restructure/src/VersionedStruct.js:42:12)
    at TTFFont._decodeTable (/home/defue/node_modules/fontkit/src/TTFFont.js:93:32)
    at TTFFont.getTable (/home/defue/node_modules/fontkit/src/TTFFont.js:69:40)
    at LayoutEngine.position (/home/defue/node_modules/fontkit/src/layout/LayoutEngine.js:106:72)
    at LayoutEngine.layout (/home/defue/node_modules/fontkit/src/layout/LayoutEngine.js:63:24)

The font is attached.
Verona-Xlight.ttf.zip

Fontkit version 1.2.1

TypeError: Cannot read property 'points' of null

Code:

var fontkit = require('fontkit');
var font = fontkit.openSync('duality.ttf');
var run = font.layout('%');
var bbox = run.glyphs[0].bbox

Error:

/home/user/fontkit/node_modules/fontkit/src/glyph/TTFGlyph.js:268
          ref1 = glyph.points;
                      ^

TypeError: Cannot read property 'points' of null
    at TTFGlyph._getContours (/home/user/fontkit/node_modules/fontkit/src/glyph/TTFGlyph.js:268:23)
    at TTFGlyph._getPath (/home/user/fontkit/node_modules/fontkit/src/glyph/TTFGlyph.js:313:23)
    at TTFGlyph.path (/home/user/fontkit/node_modules/fontkit/src/glyph/Glyph.js:86:66)
    at TTFGlyph.Glyph._getBBox (/home/user/fontkit/node_modules/fontkit/src/glyph/Glyph.js:33:18)
    at TTFGlyph.bbox (/home/user/fontkit/node_modules/fontkit/src/glyph/Glyph.js:82:66)
    at Object.<anonymous> (/home/user/fontkit/test.js:4:25)
    at Module._compile (module.js:410:26)
    at Object.Module._extensions..js (module.js:417:

10)
    at Module.load (module.js:344:32)
    at Function.Module._load (module.js:301:12)

The duality.ttf font is attached.
duality.ttf.zip
Fontkit v1.3.0

layout method missing?

When trying the example in the readme it presents me with a cute error ?!

TypeError: Object #<TTFFont> has no method 'layout'

Test with text-rendering-tests

Hi Devon, just fyi, the text rendering test suite (the one that was previously in my GitHub space) has now moved to Unicode: https://github.com/icu-project/text-rendering-tests — feel free to use it for testing fontkit. Also, if you’d like to contribute to the test suite, your contributions would be very welcome — I’ll send you the Unicode CLA if you’re interested.

GPOS table is not parsed from otf font

Hello!

For the font attached the GPOS table is not parsed while it is present in the font.
As GPOS table is not parsed the layout engine is not initialized and thus "layout" method of the font can't render Hebrew words.
Please find the font file and the screenshot from FontForge with the evidence of GPOS table availability attached.
GPOS.zip

Fontkit v1.3.0

Get font-weight value

Where in the font object would I look to obtain a font-weight value as a number (400, 500, etc) or a string (bold, normal, etc)

Also, is there something that would tell me if the font is a monospace?

Regression Error while building using Browserify

Error: tried to statically call { readFile: [Function: readFile], readFileSync: [Function: readFileSync], readdir: [Function: readdir], readdirSync: [Function: readdirSync] } as a function while parsing file: /Volumes/Development/neoScores/gustaf/node_modules/fontkit/index.js
Warning: Error running grunt-browserify. Use --force to continue.

Extend the GlyphRun object with set-serialization functions?

Right now in order to serialize a GlyphRun to something like SVG, one needs to manually run over the glyph array and work with the positional information to generate something that makes sense.

Giving the GlyphRun object its own API in addition to the glyphs and positions properties might be a good idea, so that this works:

var font = fontkit.openSync('font.ttf');
var run = font.layout('hello world');
var svg = run.toSVG();

Browser support

You state...

Fontkit is an advanced font engine for Node and the browser

...but you don't offer an explanation (for the less well-versed among us) how Fontkit can be used for the browser environment. It'd be amazing if you could add a few lines about how one would do that (i.e. without node.js).

I would expect something like a *.js file that I could embed in an HTML file. But it's probably not that easy...

Many thanks! This is a super helpful library.

Can't layout in TravelingTypewriter.otf font

Here is the code:

var fontkit = require('fontkit');
var font = fontkit.openSync('TravelingTypewriter.otf');
var run = font.layout('hello world!');

Here is the output:

/home/user/node_modules/fontkit/node_modules/brotli/build/decode.js:1
orts, require, module, __filename, __dirname) { function e(a){throw a;}var j=v
                                                                    ^
Error: Not a fixed size
    at Object.exports.resolveLength (/home/user/node_modules/fontkit/node_modules/restructure/src/utils.js:19:13)
    at ArrayT.decode (/home/user/node_modules/fontkit/node_modules/restructure/src/Array.js:22:24)
    at VersionedStruct.Struct._parseFields (/home/user/node_modules/fontkit/node_modules/restructure/src/Struct.js:53:22)
    at VersionedStruct.decode (/home/user/node_modules/fontkit/node_modules/restructure/src/VersionedStruct.js:42:12)
    at /home/user/node_modules/fontkit/node_modules/restructure/src/Pointer.js:69:30
    at CFFPointer.Pointer.decode (/home/user/node_modules/fontkit/node_modules/restructure/src/Pointer.js:79:16)
    at CFFPointer.decode (/home/user/node_modules/fontkit/src/cff/CFFPointer.js:30:42)
    at decodeOperands (/home/user/node_modules/fontkit/src/cff/CFFDict.js:36:21)
    at CFFDict.decode (/home/user/node_modules/fontkit/src/cff/CFFDict.js:96:27)
    at CFFIndex.decode (/home/user/node_modules/fontkit/src/cff/CFFIndex.js:42:30)

The font is attached. Fontkit version is 1.1.0.

TravelingTypewriter.otf.zip

Opening of font files in browser

I was unable to open the font files in browser using fontkit. The input format to fontkit is buffer but could not find a way to pass a buffer in browser, could only get an option of passing ArrayBuffer which fontkit does not accept.

JS Allocation failed - process out of memory

Code:

var fontkit = require('fontkit');
var font = fontkit.openSync('SeoulNamsan.ttf');
var run = font.layout('hello world!');

When running the code above nodejs process is killed after consuming more than 1GB of RAM with the below error:

FATAL ERROR: JS Allocation failed - process out of memory
Aborted (core dumped)

Nodejs v0.10.25
Fontkit v1.2.1
SeoulNamsan.ttf.zip

font.layout can't parse family emoji

var family = font.layout('👨‍👩‍👧‍👦👨‍👩‍👧👨‍👩‍👦‍👦');

Produces:

TypeError: Cannot read property 'codePoints' of undefined
    at AATMorxProcessor.processLigature (/Users/samanthajohn/Development/hopscotch-community/submodules/webplayer/node_modules/fontkit/src/aat/AATMorxProcessor.js:254:75)
    at /Users/samanthajohn/Development/hopscotch-community/submodules/webplayer/node_modules/fontkit/src/aat/AATMorxProcessor.js:4:59
    at AATStateMachine.process (/Users/samanthajohn/Development/hopscotch-community/submodules/webplayer/node_modules/fontkit/src/aat/AATStateMachine.js:55:11)
    at AATMorxProcessor.processSubtable (/Users/samanthajohn/Development/hopscotch-community/submodules/webplayer/node_modules/fontkit/src/aat/AATMorxProcessor.js:124:27)
    at AATMorxProcessor.process (/Users/samanthajohn/Development/hopscotch-community/submodules/webplayer/node_modules/fontkit/src/aat/AATMorxProcessor.js:81:18)
    at LayoutEngine.substitute (/Users/samanthajohn/Development/hopscotch-community/submodules/webplayer/node_modules/fontkit/src/layout/LayoutEngine.js:99:28)
    at LayoutEngine.layout (/Users/samanthajohn/Development/hopscotch-community/submodules/webplayer/node_modules/fontkit/src/layout/LayoutEngine.js:84:21)
    at TTFFont.layout (/Users/samanthajohn/Development/hopscotch-community/submodules/webplayer/node_modules/fontkit/src/TTFFont.js:218:33)
    at repl:1:19
    at REPLServer.defaultEval (repl.js:132:27)

With the Apple Color Emoji.ttf font available on Macs.

Note: chrome also cannot really parse the family emoji. To see this properly look on safari.

Cannot browserify fontkit

I tried to install the fontkit branch of pdfkit, but I am getting errors from a browserify (on Mac OS X Yosemite). I cannot find a reference to a module called ws in the code, so I really have no idea what the problem is.

I even tried to use older browserify versions in case this is a bug of browserify, but with no success. Maybe you have an idea?

$ browserify test.js
Cannot find module 'ws' from '/Users/xy/Documents/repos/test-fontkit/node_modules/fontkit/node_modules/brotli'
    at /usr/local/lib/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:50:17
    at process (/usr/local/lib/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:119:43)
    at /usr/local/lib/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:128:21
    at load (/usr/local/lib/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:60:43)
    at /usr/local/lib/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:66:22
    at /usr/local/lib/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:21:47
    at Object.oncomplete (fs.js:108:15)

$ npm ls
/Users/xy/Documents/repos/test-fontkit
└─┬ [email protected]
  ├── [email protected]
  ├── [email protected]
  ├── [email protected]
  ├─┬ [email protected]
  │ └── [email protected]
  └─┬ [email protected]
    └── [email protected]

$ cat test.js 
var fontkit = require('fontkit');

$ browserify -v
8.1.3

Full script font support.

Some script fonts draw different glyphs depending on the previous or next glyph and it appears that this library doesn't take that into account. Here's an example using the font Pacifico.

Rendered using Fontkit:
image

Same font in Sketch:
image

Notice how the Fontkit rendering is just drawing individual glyphs without "tails" to connect to the next glyph while in Sketch everything connects. Are there any plans to/is it possible to add support for this?

Can't require

Just did npm install fontkit, and tried to require it in node CLI but got this:

> require('fontkit');
TypeError: Cannot call method 'replace' of undefined
    at Object.<anonymous> (/Users/josip/tmp/node_modules/fontkit/node_modules/brotli/build/decode.js:2:462)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at Object.<anonymous> (/Users/josip/tmp/node_modules/fontkit/node_modules/brotli/decompress.js:1:76)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)

I'm using node 0.10.4 on OS X 10.11. I'm guessing I'm using a too old version of node?

Not working in browser

Output generated with
browserify index.js -o out.js

when ran in browser throws the following error:
Uncaught TypeError: Cannot read property 'replace' of undefined

Using the github source.

Not a supported font format or standard PDF font.

Guys.... the following code is returning me a Buffer instead of string

var fontkit = require('fontkit');

var font = fontkit.openSync('source/assets/media/fonts/chinese/STHeiti Light.ttc');

font.fonts.forEach(font =>{
    console.log(font.postscriptName)
    console.log(font.postscriptName.toString('utf8'))
})

//logs
<Buffer 53 54 48 65 69 74 69 54 43 2d 4c 69 67 68 74>
STHeitiTC-Light
<Buffer 53 54 48 65 69 74 69 53 43 2d 4c 69 67 68 74>
STHeitiSC-Light

the problem is that due to this (i believe)... i always get wrong mismatching font family names..

doc.registerFont('Main', 'source/assets/media/fonts/chinese/STHeiti Light.ttc', 'STHeitiTC-Light')

throws me

throw new Error('Not a supported font format or standard PDF font.');
        ^
Error: Not a supported font format or standard PDF font.

i think this is the reason because... i was using this script to indentify the font postscriptName and even wrote an entire tutorial internally with pictures demonstrating.. but then sunddenly for the first time it started returning a buffer... odd

i did manange to get this working before... so i am absolutely sure its not a problem with the font.. as i have few pdf generated using the same script that im using right now... this problem only showed up after i clean up the whole node_modules and installed again due to there were too many modules inside which i had already deleted from my package.json.. then after reinstalling.... got this error..

Support for Source Han Sans or Noto Sans CJK fonts (OpenType)

Hello,

I've been trying to use fontkit with pdfkit (fontkit branch) in order to generate PDFs with Chinese characters. Currently, the best free fonts for supporting CJK are OTF fonts, such as Source Han Sans and Noto Sans, but they don't seem to be supported in fontkit. Using either the superset .ttc, or individual .otf fonts from these projects results in an error of the format not being supported. From my initial digging into the repo, it looks like opentype support isn't wired in yet, correct?

Is there anyway to get glyph name?

Currently, I have a need of getting a glyph name from a glyph / glyph id. That can be easily done in other font-related libraries (in other languages, yeah).

However I found the font.post.names doesn't return correct glyph name and also its length doesn't match the total number of glyphs. Trying out in conjunction with font.post.glyphNameIndex doesn't work also.

Is there an official way to do it? Or how can I achieve that?

Decoding name records of TTF/TTC bundled with Mac

I tried to get name records of a TTF/TTC bundled with Mac, and found that some values are decoded as buffers, instead of as strings. For example:

$ node
> const fontkit = require('fontkit')
undefined
> const font = fontkit.openSync('/Library/Fonts/BigCaslon.ttf')
undefined
> font.postscriptName
<Buffer 42 69 67 43 61 73 6c 6f 6e 2d 4d 65 64 69 75 6d>
> font.fullName
<Buffer 42 69 67 20 43 61 73 6c 6f 6e 20 4d 65 64 69 75 6d>
> font.familyName
<Buffer 42 69 67 20 43 61 73 6c 6f 6e>
> font.subfamilyName
'Medium'
> font.name
{ version: 0,
  count: 43,
  stringOffset: 522,
  records:
   { fontFeatures: { '0-1': [Object], English: [Object] },
     copyright: { English: <Buffer 43 6f 70 79 72 69 67 68 74 20 28 63 29 20 31 39 39 34 20 43 61 72 74 65 72 20 26 20 43 6f 6e 65 20 54 79 70 65 2c 20 49 6e 63 2e 20 41 6c 6c 20 72 69 ... > },
     fontFamily: { English: <Buffer 42 69 67 20 43 61 73 6c 6f 6e> },
     fontSubfamily:
      { English: 'Medium',
        Chinese: '中等',
        Danish: 'Medium',
        German: 'Halbfett',
        Finnish: 'Normaali',
        French: 'Moyen',
        Italian: 'Medio',
        Japanese: 'ミディアム',
        Korean: '중간체',
        Dutch: 'Medium',
        'Norwegian (Bokmal)': 'Medium',
        Portuguese: 'Médio',
        Russian: 'Средний',
        Swedish: 'Normal',
        'Spanish (Modern Sort)': 'Media' },
     uniqueSubfamily: { English: <Buffer 42 69 67 20 43 61 73 6c 6f 6e 20 4d 65 64 69 75 6d 3b 20 31 30 2e 30 64 32 65 31 3b 20 32 30 31 34 2d 30 35 2d 33 30> },
     fullName: { English: <Buffer 42 69 67 20 43 61 73 6c 6f 6e 20 4d 65 64 69 75 6d> },
     version: { English: <Buffer 31 30 2e 30 64 32 65 31> },
     postscriptName: { English: <Buffer 42 69 67 43 61 73 6c 6f 6e 2d 4d 65 64 69 75 6d> },
     trademark: { English: <Buffer 22 42 69 67 20 43 61 73 6c 6f 6e 22 20 69 73 20 61 20 54 72 61 64 65 6d 61 72 6b 20 6f 66 20 43 61 72 74 65 72 20 26 20 43 6f 6e 65 20 54 79 70 65 2c ... > } } }
  • node 6.5.0
  • OS X 10.11.6
  • BigCaslon.ttf 10.0d2e1

Error when building fontkit

I've downloaded the master branch and try to build it by issuing the below commands"

cd fontkit-master
make

Here is the output I get:

babel-node src/opentype/shapers/gen-use.js
/usr/local/lib/node_modules/babel-cli/node_modules/babel-core/lib/transformation/file/options/option-manager.js:334
        throw e;
        ^

TypeError: Cannot read property 'merge' of undefined (While processing preset: "/home/defue/Temp/fontkit/node_modules/babel-preset-es2015/lib/index.js")
    at Object.<anonymous> (/home/defue/Temp/fontkit/node_modules/babel-plugin-transform-es2015-classes/lib/vanilla.js:52:32)
    at Module._compile (module.js:410:26)
    at loader (/usr/local/lib/node_modules/babel-cli/node_modules/babel-register/lib/node.js:144:5)
    at Object.require.extensions.(anonymous function) [as .js] (/usr/local/lib/node_modules/babel-cli/node_modules/babel-register/lib/node.js:154:7)
    at Module.load (module.js:344:32)
    at Function.Module._load (module.js:301:12)
    at Module.require (module.js:354:17)
    at require (internal/module.js:12:17)
    at Object.<anonymous> (/home/defue/Temp/fontkit/node_modules/babel-plugin-transform-es2015-classes/lib/loose.js:21:16)
    at Module._compile (module.js:410:26)
Makefile:9: recipe for target 'src/opentype/shapers/use.trie' failed
make: *** [src/opentype/shapers/use.trie] Error 1

babel-node version 6.18.0

very large memory footprint?

It would appear that fontkit, without loading in any fonts, takes up some 970MB of RAM, which is... pretty much impossibly large, since it leaves no RAM to actually run a program with on affordable VMs.

I simply used the following code:

var fontkit = require("fontkit");
var readline = require('readline');
var rl = readline.createInterface({ input: process.stdin, output: process.stdout });
rl.question("What do you think of node.js? ", function(answer) {
  console.log("Thank you for your valuable feedback:", answer);
  rl.close();
});

With the readline code to make sure the node process stays alive - the footprint for a node process using only readline is 16MB, so fontkit is taking up a tremendous amount of space without having started doing anything.

I don't have any pointers right now that might bring that footprint down, but thought it worth filing as an issue to revisit.

Fonts without postscript name fails

If a TTF or Woff font doesn't have a postscript name and you try to use it, an exception is thrown. The error occurs at TTFFont.js "get postscriptName()" method. Adding a null pointer check fixes it. I will do a pull request also.

TypeError: Cannot read property 'length' of null

Code:

var fontkit = require('fontkit');
var font = fontkit.openSync('Confetti Regular.ttf');
var run = font.layout('hello world!');

Output:

/home/defue/node_modules/brotli/build/decode.js:1
orts, require, module, __filename, __dirname) { function e(a){throw a;}var j=v
                                                                    ^
TypeError: Cannot read property 'length' of null
    at GSUBProcessor.OTProcessor.findScript (/home/defue/node_modules/fontkit/src/opentype/OTProcessor.js:29:28)
    at GSUBProcessor.OTProcessor.selectScript (/home/defue/node_modules/fontkit/src/opentype/OTProcessor.js:56:24)
    at GSUBProcessor.OTProcessor (/home/defue/node_modules/fontkit/src/opentype/OTProcessor.js:20:12)
    at new GSUBProcessor (/home/defue/node_modules/fontkit/src/opentype/GSUBProcessor.js:16:50)
    at new OTLayoutEngine (/home/defue/node_modules/fontkit/src/opentype/OTLayoutEngine.js:20:30)
    at new LayoutEngine (/home/defue/node_modules/fontkit/src/layout/LayoutEngine.js:25:129)
    at TTFFont.layout (/home/defue/node_modules/fontkit/src/TTFFont.js:216:30)
    at Object.<anonymous> (/home/defue/Tagul/svn/Frontend/canvasForm/components/fontkit/test.js:3:16)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)

Nodejs v0.10.25
Fontkit v
Confetti Regular.ttf.zip
1.2.1

Correct orientation?

Sorry for the elementary question. I'm following the example from fonttest to turn a text string into an SVG path. When you load the resulting SVG file in the browser, the glyphs are flipped.

I understand that by convention, the y-axis for SVG points downward whereas for fonts it points upward. My question is: what is the best way to work with the path data so that the glyphs appear with proper orientation? Can I generate the path data so that it appears right-side-up to begin with Should I wrap everything in a <g transform="scale(1,-1)">?

font.widthOfGlyph() not implemented

font.widthOfGlyph(glyph_id)

Returns the advance width (described above) for a single glyph id.

While the font.widthOfGlyph() method is listed in README.md, it doesn't seem to be implemented.

> font.widthOfGlyph(1)
TypeError: font.widthOfGlyph is not a function

Export path to SVG

First of all, thank you very much for the library. This looks super helpful.

I was trying to get an SVG for a string or letter, so that I can further process it in paper.js.

Now, what I receive from this method var svg = run.glyphs[0].path.toSVG(); is not what I expected. I received a complex series like this:

M219 1233L211 722Q247 712 319 712L397 712L397 755Q397 849 383 1037.5Q369 1226 369 1320Q369 1343 386.5 1358.5Q404 1374 417.5 1374Q431 1374 441 [...]

However, I would have expected a well-formatted XML/SVG string.

I am a total noob as should be obvious by now. But how would I be able to obtain an SVG string from the series above?

UnicodeLayoutEngine.positionGlyphs method doesn't position Hebrew (RTL) words

UnicodeLayoutEngine.positionGlyphs method is supposed to position glyphs when no layout engine is defined. To my understanding it should detect RTL languages based on script variable and position them properly but it doesn't.

Code:

var fontkit = require('fontkit');
var font = fontkit.openSync('Nesheekot-Medium.otf');
var run = font.layout('עברית');

for (var i = 0, glyph, position; i < run.glyphs.length; i++) {
    glyph = run.glyphs[i];
    position = run.positions[i];
    console.log("Glyph id: " + glyph.id + " codePoint: " + glyph.codePoints[0] + " xAdvance: " + position.xAdvance);
}

Output:

Glyph id: 172 codePoint: 1506 xAdvance: 430
Glyph id: 155 codePoint: 1489 xAdvance: 551
Glyph id: 178 codePoint: 1512 xAdvance: 528
Glyph id: 163 codePoint: 1497 xAdvance: 164
Glyph id: 180 codePoint: 1514 xAdvance: 492

The output should be reversed as the text is RTL Hebrew.

Fontkit v1.3.0
Nesheekot-Medium.otf.zip

Exception "Unknown op 0" with some woff fonts

Fontkit (used in PDFKit) throws an exception with some fonts in this folder:

Most are testing fonts with lots of missing glyphs but apparently that's not the issue because they work as expected if converted to TTF.

Error: Unknown op: 0
    at parse (http://pdfkit.org/demo/bundle.js:39197:23)
    at CFFGlyph._getPath (http://pdfkit.org/demo/bundle.js:39213:7)
    at CFFGlyph.get (http://pdfkit.org/demo/bundle.js:38136:19)
    at CFFGlyph.descriptor.get (http://pdfkit.org/demo/bundle.js:29165:21)
    at CFFGlyph._getCBox (http://pdfkit.org/demo/bundle.js:37980:18)
    at CFFGlyph.get (http://pdfkit.org/demo/bundle.js:38111:19)
    at CFFGlyph.descriptor.get (http://pdfkit.org/demo/bundle.js:29165:21)
    at CFFGlyph._getMetrics (http://pdfkit.org/demo/bundle.js:38024:22)
    at CFFGlyph.get (http://pdfkit.org/demo/bundle.js:38147:19)
    at CFFGlyph.descriptor.get (http://pdfkit.org/demo/bundle.js:29165:21)

release version with path fixes

The issue you found with require using upper case paths is affecting our build. Would you mind releasing a new version of the lib to NPM?

Thanks a lot.

Enumerate through all glyphs in font

Hi,

Great library. I was wondering whether it would be possible to get the full list of glyphs that are contained in a font and their unicode representations.

As far as I understand, right now there's only the ability to get single code characters from the character set. It would be cool if you could get multiple code points like U+1F468 U+200D U+1F469 U+200D U+1F467 U+200D U+1F467 and then get the glyph for their combination - 👨‍👩‍👧‍👦.

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.