diff --git a/README.md b/README.md index 5887873d..7d53fd01 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ If you plan on improving or debugging opentype.js, you can: ## Usage -### Loading a font +### Loading a WOFF/OTF/TTF font ```js // case 1: from an URL @@ -81,17 +81,41 @@ const buffer = require('fs').promises.readFile('./my.woff'); const buffer = document.getElementById('myfile').files[0].arrayBuffer(); // if running in async context: -const font = opentype.parse(await data); -console.log(font.supported); +const font = opentype.parse(await buffer); +console.log(font); // if not running in async context: buffer.then(data => { const font = opentype.parse(data); - // ... play with `font` ... - console.log(font.supported); + console.log(font); }) ``` +### Loading a WOFF2 font + +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 having a much heavier opentype.js library (~120KB => ~1400KB). + +To solve this: Decompress the font beforehand (for example with [fontello/wawoff2](https://github.com/fontello/wawoff2)). + +```js +// promise-based utility to load libraries using the good old - - - -
-

+ .wrapper span { + text-align: center; + background: #ddd; + display: block; + } + + +
+

This font is generated dynamically in the browser.

- + Download Font
-
+ - - - diff --git a/docs/examples/font-editor.html b/docs/examples/font-editor.html index a0b3072b..7cc0aff8 100644 --- a/docs/examples/font-editor.html +++ b/docs/examples/font-editor.html @@ -1,587 +1,583 @@ - - - - Font Editor - - - - -
- -

Experimental font editor

-
-
-
-
- - - -
+ +Font Editor + + +
+ Download font (.OTF) +

Experimental font editor

+
+
+
+
+ + +
-
-
- - - Shift-click a point to remove it -
- - - - - - - + w = Math.max(w, x); + } + var newGlyph = new opentype.Glyph({ + name: ttfName, + unicode: c.charCodeAt(0), + advanceWidth: (w + 1) * TTF_SCALE, + path: p + }); + otGlyphs.push(newGlyph); + } + var oFont = new opentype.Font({ + familyName: 'Pyramid', + styleName: 'Regular', + unitsPerEm: 1000, + ascender: 800, + descender: -200, + glyphs: otGlyphs + }); + console.log(oFont); + const a = document.getElementById("download-font"); + a.href = window.URL.createObjectURL(new Blob([oFont.toArrayBuffer()], {type: "font/otf"})); +} + +function onAddPoint() { + var newX = Math.floor(Math.random() * 8); + var newY = Math.floor(Math.random() * 8); + gPoints.push([newX, newY]); + dumpGlyphMap(); + draw(); +} + +function onRemovePoint() { + delete gPoints.pop(); + dumpGlyphMap(); + draw(); +} + +function packValues() { + var s = ''; + for (var i = 0; i < arguments.length; i += 1) { + var v = arguments[i]; + if (v >= 0 && i > 0) { + s += ' '; + } + + s += floatToString(v); + } + + return s; +} + +function toPathData(points, scale) { + var d = ''; + for (var i = 0; i < points.length; i += 1) { + if (i === 0) { + d += 'M'; + } else { + d += 'L'; + } + d += points[i][0] * scale; + d += ' '; + d += (10 - points[i][1]) * scale; + } + d += 'Z'; + return d; +} + +function onSelectGlyph(e) { + var target = e.target; + if (!target.getAttribute('data-character')) { + target = target.parentNode; + } + gGlyph = target.getAttribute('data-character'); + gPoints = gGlyphMap[gGlyph]; + drawGlyphList(); + draw(); +} + +function drawGlyphList() { + var container = document.getElementById('glyph-list'); + container.innerHTML = ''; + var characters = Object.keys(gGlyphMap); + for (var i = 0; i < characters.length; i++) { + var c = characters[i]; + var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); + var d = toPathData(gGlyphMap[c], 7); + svg.innerHTML = ''; + container.appendChild(svg); + svg.setAttribute('data-character', c); + if (gGlyph === c) { + svg.classList.add('active'); + } + svg.addEventListener('click', onSelectGlyph); + } +} + +function onChangePreviewText(e) { + gPreviewText = e.target.value; + drawPreview(); +} + +// Mouse move +canvas.addEventListener('mousemove', onMouseMove); +canvas.addEventListener('mousedown', onMouseDown); +canvas.addEventListener('mouseup', onMouseUp); +document.getElementById('add-point').addEventListener('click', onAddPoint); +document.getElementById('remove-point').addEventListener('click', onRemovePoint); +document.getElementById('download-font').addEventListener('click', downloadFont); +document.getElementById('preview-text-field').addEventListener('input', onChangePreviewText); + +drawGlyphList(); +draw(); +dumpGlyphMap(); + diff --git a/docs/examples/reading-writing.html b/docs/examples/reading-writing.html index aa5e9dc8..d7c27d9b 100644 --- a/docs/examples/reading-writing.html +++ b/docs/examples/reading-writing.html @@ -1,87 +1,80 @@ - - - OpenType writing - - - -
-

+ +OpenType writing + + +
+

This font is generated dynamically in the browser.

- + Download Font
-
+ diff --git a/docs/font-inspector.html b/docs/font-inspector.html index 4d763a2e..52e1ea14 100644 --- a/docs/font-inspector.html +++ b/docs/font-inspector.html @@ -1,12 +1,10 @@ - - - opentype.js font inspector - - - - - + +opentype.js font inspector + + + +

opentype.js

diff --git a/docs/glyph-inspector.html b/docs/glyph-inspector.html index 792e5e64..60732306 100644 --- a/docs/glyph-inspector.html +++ b/docs/glyph-inspector.html @@ -1,12 +1,10 @@ - - - opentype.js glyph inspector - - - - - + +opentype.js glyph inspector + + + +

opentype.js

diff --git a/docs/index.html b/docs/index.html index cc507a20..ed92e27e 100755 --- a/docs/index.html +++ b/docs/index.html @@ -1,12 +1,10 @@ - - - opentype.js – JavaScript parser/writer for OpenType and TrueType fonts. - - - - - + +opentype.js – JavaScript parser/writer for OpenType and TrueType fonts. + + + +

opentype.js

@@ -209,14 +207,13 @@

Free Software

renderText(); } -const loadScript = (src) => new Promise((onload, onerror) => document.head.append(Object.assign(document.createElement('script'), {src, onload, onerror}))); +const loadScript = (src) => new Promise((onload) => document.head.append(Object.assign(document.createElement('script'), {src, onload}))); async function display(file, name) { form.fontname.innerText = name; const isWoff2 = name.endsWith('.woff2'); if (isWoff2 && !window.Module) { const wasmReady = new Promise((onRuntimeInitialized) => window.Module = { onRuntimeInitialized }); - await loadScript('https://unpkg.com/wawoff2@2.0.1/build/decompress_binding.js'); // wawoff2 is globaly loaded as 'Module' - await wasmReady; // WASM has called our onRuntimeInitialized() resolver + await loadScript('https://unpkg.com/wawoff2@2.0.1/build/decompress_binding.js').then(() => wasmReady); } try { const data = await file.arrayBuffer(); @@ -237,5 +234,3 @@

Free Software

const fontFileName = 'fonts/FiraSansMedium.woff'; display(await fetch(fontFileName), fontFileName); - -