Skip to content

Commit 476887b

Browse files
committed
Add woff-to-otf
1 parent aa8ad76 commit 476887b

File tree

2 files changed

+137
-2
lines changed

2 files changed

+137
-2
lines changed

src/opentype.mjs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import meta from './tables/meta.mjs';
3838
import gasp from './tables/gasp.mjs';
3939
import svg from './tables/svg.mjs';
4040
import { PaletteManager } from './palettes.mjs';
41+
import { woff_to_otf } from './woff-to-otf.mjs';
4142
/**
4243
* The opentype library.
4344
* @namespace opentype
@@ -436,7 +437,7 @@ function parseBuffer(buffer, opt={}) {
436437
font.tables.meta = meta.parse(metaTable.data, metaTable.offset);
437438
font.metas = font.tables.meta;
438439
}
439-
440+
440441
font.palettes = new PaletteManager(font);
441442

442443
return font;
@@ -473,5 +474,8 @@ export {
473474
parse as _parse,
474475
parseBuffer as parse,
475476
load,
476-
loadSync
477+
loadSync,
478+
parseWOFFTableEntries,
479+
uncompressTable,
480+
woff_to_otf
477481
};

src/woff-to-otf.mjs

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// CAUTION this is a dependency cycle, but since the dependencies are
2+
// on execution time of woff_to_otf it only looks statically like a problem.
3+
// still, maybe parseWOFFTableEntries and uncompressTable should not be
4+
// in opentype.js or maybe woff_to_otf could move into opentype.js
5+
import { // eslint-disable-line
6+
parseWOFFTableEntries,
7+
uncompressTable
8+
} from './opentype.mjs';
9+
10+
import parse from './parse.mjs';
11+
import { encode } from './types.mjs';
12+
13+
// I looked at https://github.com/mondeja/woff2otf/blob/master/src/woff2otf.js
14+
// but I'm using opentype.js infrastructure.
15+
function woff_to_otf(buffer) {
16+
if (buffer.constructor !== ArrayBuffer)
17+
buffer = new Uint8Array(buffer).buffer;
18+
const data = new DataView(buffer, 0)
19+
, out = []
20+
, signature = parse.getTag(data, 0)
21+
;
22+
23+
if (signature !== 'wOFF')
24+
throw new Error(`TYPE ERROR signature must be wOFF but is: "${signature}"`);
25+
26+
// need flavour??? -> opentype header syff!
27+
const flavor = parse.getTag(data, 4)
28+
, numTables = parse.getUShort(data, 12)
29+
, tableEntries = parseWOFFTableEntries(data, numTables)
30+
, max = []
31+
;
32+
for (let n = 0; n < 64; n++) {
33+
if (Math.pow(2, n) > numTables)
34+
break;
35+
max.splice(0, Infinity, n, Math.pow(2, n));
36+
}
37+
const searchRange = max[1] * 16
38+
, entrySelector = max[0]
39+
, rangeShift = numTables * 16 - searchRange
40+
;
41+
42+
out.push(
43+
...encode.TAG(flavor)
44+
, ...encode.USHORT(numTables)
45+
, ...encode.USHORT(searchRange)
46+
, ...encode.USHORT(entrySelector)
47+
, ...encode.USHORT(rangeShift)
48+
);
49+
let offset = out.length;
50+
for (let i=0; i<numTables; i++) {
51+
// This is done in parseWOFFTableEntries already, minus the checksum:
52+
// tableEntries.push({tag: tag, offset: offset, compression: compression,
53+
// compressedLength: compLength, length: origLength});
54+
// Hence, we just amend the checksum.
55+
// Maybe, checksum could be added in parseWOFFTableEntries
56+
57+
// let p = 44; // offset to the first table directory entry.
58+
const pointerBase = 44 + i * 20;
59+
// tableDirectoryEntries.push({
60+
// tag: parse.getTag(data, pointerBase)
61+
// , offset: parse.getULong(data, pointerBase + 4)
62+
// , compLength: parse.getULong(data, pointerBase + 8)
63+
// , origLength: parse.getULong(data, pointerBase + 12)
64+
// , origChecksum: parse.getULong(data, pointerBase + 16)
65+
// });
66+
// p += 20;
67+
tableEntries[i].checksum = parse.getULong(data, pointerBase + 16);
68+
// offset += 4 * 4;
69+
}
70+
offset += numTables * 16;
71+
72+
for (let i=0; i<numTables; i++) {
73+
const tableEntry = tableEntries[i];
74+
out.push(
75+
...encode.TAG(tableEntry.tag)
76+
, ...encode.ULONG(tableEntry.checksum)
77+
, ...encode.ULONG(offset)
78+
, ...encode.ULONG(tableEntry.length)
79+
);
80+
tableEntry.outOffset = offset;
81+
offset += tableEntry.length;
82+
if ((offset % 4) !== 0)
83+
offset += 4 - (offset % 4);
84+
}
85+
const buffers = []
86+
, initialData = new Uint8Array(out.length)
87+
;
88+
for (let i=0,l=out.length; i<l; i++)
89+
initialData[i] = out[i];
90+
buffers.push(initialData);
91+
92+
93+
for (let i=0; i<numTables; i++) {
94+
const tableEntry = tableEntries[i]
95+
, table = uncompressTable(data, tableEntry) // => {data: view, offset: 0};
96+
// FIXME: we should rather just append the bytes to a new buffer
97+
// no need to parse into an array ...
98+
// , p = new parse.Parser(table.data, table.offset)
99+
;
100+
101+
102+
offset = tableEntry.outOffset + tableEntry.length;
103+
const padding = (offset % 4) !== 0
104+
? 4 - (offset % 4)
105+
: 0
106+
;
107+
// out.push(
108+
// ...p.parseByteList(tableEntry.length)
109+
// , ...Array(padding).fill(0) // new ArrayBuffer(padding)
110+
// );
111+
buffers.push(
112+
new DataView(table.data.buffer, table.offset, tableEntry.length)
113+
, new ArrayBuffer(padding)
114+
);
115+
}
116+
117+
const result = new Uint8Array(buffers.reduce((accum, buffer)=>accum+buffer.byteLength, 0));
118+
buffers.reduce((offset, buffer)=>{
119+
result.set(buffer, offset);
120+
return offset + buffer.byteLength;
121+
}, 0);
122+
return result.buffer;
123+
//const outArray = new Uint8Array(out.length);
124+
//for (let i=0,l=out.length; i<l; i++)
125+
// outArray[i] = out[i];
126+
//return outArray.buffer;
127+
}
128+
129+
export {
130+
woff_to_otf
131+
};

0 commit comments

Comments
 (0)