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

Sane buildflow #703

Merged
merged 4 commits into from May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
57 changes: 26 additions & 31 deletions README.md
Expand Up @@ -41,7 +41,7 @@ Select one of the following sources in the next example:

<!-- using module declaration (need full path) -->
<script type=module>
import { parse } from "https://unpkg.com/opentype.js/dist/opentype.module.js";
import { parse } from "https://unpkg.com/opentype.js/dist/opentype.mjs";
parse(...);
</script>
```
Expand Down Expand Up @@ -80,14 +80,18 @@ If you plan on improving or debugging opentype.js, you can:

### Loading a WOFF/OTF/TTF font

This is done in two steps: first, we load the font file into an `ArrayBuffer` ...
```js
// case 1: from an URL
// either from an URL
const buffer = fetch('/fonts/my.woff').then(res => res.arrayBuffer());
// case 2: from filesystem (node)
// ... or from filesystem (node)
const buffer = require('fs').promises.readFile('./my.woff');
// case 3: from an <input type=file id=myfile>
// ... or from an <input type=file id=myfile> (browser)
const buffer = document.getElementById('myfile').files[0].arrayBuffer();
```

... then we `.parse()` it into a `Font` instance
```js
// if running in async context:
const font = opentype.parse(await buffer);
console.log(font);
Expand All @@ -99,7 +103,8 @@ buffer.then(data => {
})
```

### Loading a WOFF2 font
<details>
<summary>Loading a WOFF2 font</summary>

WOFF2 Brotli compression perform [29% better](https://www.w3.org/TR/WOFF20ER/#appendixB) than it WOFF predecessor.
But this compression is also more complex, and would result in a much heavier (&gt;10×!) opentype.js library (≈120KB => ≈1400KB).
Expand All @@ -123,30 +128,14 @@ if (!window.Module) {
// decompress before parsing
const font = opentype.parse(Module.decompress(await buffer));
```
</details>

### Loading a font (1.x style)

This example relies on the deprecated `.load()` method
### Craft a font

```js
// case 1: from an URL
const font = opentype.load('./fonts/my.woff', {}, {isUrl: true});
// case 2: from filesystem
const font = opentype.load('./fonts/my.woff', {}, {isUrl: false});

// ... play with `font` ...
console.log(font.supported);
```
It is also possible to craft a Font from scratch by defining each glyph bézier paths.

### Writing a font
Once you have a `Font` object (either by using `opentype.load()` or by creating a new one from scratch) you can write it
back out as a binary file.

In the browser, you can use `Font.download()` to instruct the browser to download a binary .OTF file. The name is based
on the font name.
```javascript
// Create the bézier paths for each of the glyphs.
// Note that the .notdef glyph is required.
// this .notdef glyph is required.
const notdefGlyph = new opentype.Glyph({
name: '.notdef',
advanceWidth: 650,
Expand All @@ -164,21 +153,27 @@ const aGlyph = new opentype.Glyph({
path: aPath
});

const glyphs = [notdefGlyph, aGlyph];
const font = new opentype.Font({
familyName: 'OpenTypeSans',
styleName: 'Medium',
unitsPerEm: 1000,
ascender: 800,
descender: -200,
glyphs: glyphs});
font.download();
glyphs: [notdefGlyph, aGlyph]});
```

If you want to inspect the font, use `font.toTables()`
to generate an object showing the data structures that map directly to binary values.
If you want to get an `ArrayBuffer`, use `font.toArrayBuffer()`.
### Saving a Font

Once you have a `Font` object (from crafting or from `.parse()`) you can save it back out as file.

```js
// using node:fs
fs.writeFileSync("out.otf", Buffer.from(font.toArrayBuffer()));

// using the browser to createElement a <a> that will be clicked
const href = window.URL.createObjectURL(new Blob([font.toArrayBuffer()]), {type: "font/opentype"});
Object.assign(document.createElement('a'), {download: "out.otf", href}).click();
```

### The Font object
A Font represents a loaded OpenType font file. It contains a set of glyphs and methods to draw text on a drawing context, or to get a path representing the text.
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/creating-fonts.html
Expand Up @@ -44,7 +44,7 @@ <h1><output name="fontFamilyName"></output></h1>
</form>

<script type="module">
import * as opentype from "/dist/opentype.module.js";
import * as opentype from "/dist/opentype.mjs";
function hexDump(bytes) {
var hexString = bytes.map(function(v) {
var h = v.toString(16);
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/font-editor.html
Expand Up @@ -174,7 +174,7 @@ <h1>Experimental font editor</h1>

<textarea id="code"></textarea>
<script type="module">
import * as opentype from "/dist/opentype.module.js";
import * as opentype from "/dist/opentype.mjs";

function linePoint(t, x1, y1, x2, y2) {
return [x1 + t * (x2 - x1),
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/reading-writing.html
Expand Up @@ -42,7 +42,7 @@ <h1><output name="fontFamilyName"></output></h1>
</form>

<script type="module">
import * as opentype from "/dist/opentype.module.js";
import * as opentype from "/dist/opentype.mjs";

// Create a canvas and adds it to the document.
// Returns the 2d drawing context.
Expand Down
6 changes: 3 additions & 3 deletions docs/examples/typescript/index.ts
@@ -1,9 +1,9 @@

import opentype from '../../dist/opentype.module'
import opentype from '../../dist/opentype.mjs'
console.log(opentype)
// or
import { load } from '../../dist/opentype.module'
import { load } from '../../dist/opentype.mjs'
console.log(load)
// or
import * as mySpecialOpentype from '../../dist/opentype.module'
import * as mySpecialOpentype from '../../dist/opentype.mjs'
console.log(mySpecialOpentype)
2 changes: 1 addition & 1 deletion docs/font-inspector.html
Expand Up @@ -99,7 +99,7 @@ <h1>Free Software</h1>


<script type="module">
import * as opentype from "/dist/opentype.module.js";
import * as opentype from "/dist/opentype.mjs";

var font = null;
const fontSize = 32;
Expand Down
2 changes: 1 addition & 1 deletion docs/glyph-inspector.html
Expand Up @@ -69,7 +69,7 @@ <h1>Free Software</h1>


<script type="module">
import * as opentype from "/dist/opentype.module.js";
import * as opentype from "/dist/opentype.mjs";

window.opentype = opentype;

Expand Down
2 changes: 1 addition & 1 deletion docs/index.html
Expand Up @@ -76,7 +76,7 @@ <h1>Free Software</h1>


<script type="module">
import * as opentype from "/dist/opentype.module.js";
import * as opentype from "/dist/opentype.mjs";

const form = document.forms.demo;
form.oninput = renderText;
Expand Down
2 changes: 1 addition & 1 deletion docs/module.html
@@ -1,4 +1,4 @@
<script type="module">
import * as ot from '/dist/opentype.module.js';
import * as ot from '/dist/opentype.mjs';
console.log(ot)
</script>
43 changes: 0 additions & 43 deletions eslint-local-rules.js

This file was deleted.

50 changes: 50 additions & 0 deletions eslint.config.mjs
@@ -0,0 +1,50 @@
import js from "@eslint/js";

export default [
js.configs.recommended,
{
languageOptions: {
ecmaVersion: 2018,
sourceType: "module",
globals: {
console: "readonly",
// ugly platform-dependant classes and objects
DecompressionStream: "readonly",
Response: "readonly",
TextDecoder: "readonly",
SVGPathElement: "readonly",
DOMParser: "readonly",
Image: "readonly",
document: "readonly",
}
},
rules: {
"indent": [
"error",
4,
{
"SwitchCase": 1
}
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"no-restricted-syntax": [
"error",
{
"message": "For consistency, Use `for()` loops instead of `.forEach()`",
"selector": "MemberExpression > Identifier[name=\"forEach\"]"
}
]
}
}
]