@grida/refig 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  exportSettingToRenderOptions,
7
7
  figFileToRestLikeDocument,
8
8
  iofigma
9
- } from "./chunk-YI7PIULZ.mjs";
9
+ } from "./chunk-INJ5F2RK.mjs";
10
10
 
11
11
  // cli.ts
12
12
  import {
@@ -15,13 +15,2449 @@ import {
15
15
  mkdirSync,
16
16
  writeFileSync,
17
17
  existsSync,
18
- statSync
18
+ statSync,
19
+ mkdtempSync,
20
+ createReadStream
19
21
  } from "fs";
20
22
  import path from "path";
23
+ import { tmpdir } from "os";
21
24
  import { program } from "commander";
25
+
26
+ // ../../node_modules/.pnpm/@grida+fonts@0.0.0/node_modules/@grida/fonts/dist/chunk-WQYZ3GYH.mjs
27
+ var Typr;
28
+ ((Typr2) => {
29
+ function findTable(data, tab, foff) {
30
+ const bin = Typr2.B;
31
+ const numTables = bin.readUshort(data, foff + 4);
32
+ let offset = foff + 12;
33
+ for (let i = 0; i < numTables; i++) {
34
+ const tag = bin.readASCII(data, offset, 4);
35
+ const checkSum = bin.readUint(data, offset + 4);
36
+ const toffset = bin.readUint(data, offset + 8);
37
+ const length = bin.readUint(data, offset + 12);
38
+ if (tag == tab) return [toffset, length];
39
+ offset += 16;
40
+ }
41
+ return null;
42
+ }
43
+ Typr2.findTable = findTable;
44
+ function parse(buff) {
45
+ const bin = Typr2.B;
46
+ const readFont = function(data2, idx, offset, tmap2) {
47
+ const T2 = Typr2.T;
48
+ const prsr = {
49
+ cmap: T2.cmap,
50
+ head: T2.head,
51
+ hhea: T2.hhea,
52
+ maxp: T2.maxp,
53
+ hmtx: T2.hmtx,
54
+ name: T2.name,
55
+ "OS/2": T2.OS2,
56
+ post: T2.post,
57
+ loca: T2.loca,
58
+ kern: T2.kern,
59
+ glyf: T2.glyf,
60
+ "CFF ": T2.CFF,
61
+ GSUB: T2.GSUB,
62
+ CBLC: T2.CBLC,
63
+ CBDT: T2.CBDT,
64
+ "SVG ": T2.SVG,
65
+ COLR: T2.colr,
66
+ CPAL: T2.cpal,
67
+ sbix: T2.sbix,
68
+ fvar: T2.fvar,
69
+ gvar: T2.gvar,
70
+ avar: T2.avar,
71
+ STAT: T2.STAT,
72
+ HVAR: T2.HVAR
73
+ };
74
+ const obj = { _data: data2, _index: idx, _offset: offset };
75
+ for (const t in prsr) {
76
+ const tab = Typr2.findTable(data2, t, offset);
77
+ if (tab) {
78
+ const off = tab[0];
79
+ let tobj = tmap2[off];
80
+ if (tobj == null) tobj = prsr[t].parseTab(data2, off, tab[1], obj);
81
+ obj[t] = tmap2[off] = tobj;
82
+ }
83
+ }
84
+ return obj;
85
+ };
86
+ function woffToOtf(data2) {
87
+ const numTables = bin.readUshort(data2, 12);
88
+ const totalSize = bin.readUint(data2, 16);
89
+ const otf = new Uint8Array(totalSize);
90
+ let toff = 12 + numTables * 16;
91
+ bin.writeASCII(otf, 0, "OTTO");
92
+ bin.writeUshort(otf, 4, numTables);
93
+ let off = 44;
94
+ for (let i = 0; i < numTables; i++) {
95
+ const tag2 = bin.readASCII(data2, off, 4);
96
+ const tof = bin.readUint(data2, off + 4);
97
+ const cLe = bin.readUint(data2, off + 8);
98
+ const oLe = bin.readUint(data2, off + 12);
99
+ off += 20;
100
+ let tab = data2.slice(tof, tof + cLe);
101
+ if (cLe != oLe) {
102
+ console.warn("pako inflate not available, using original data");
103
+ }
104
+ const to = 12 + i * 16;
105
+ bin.writeASCII(otf, to, tag2);
106
+ bin.writeUint(otf, to + 8, toff);
107
+ bin.writeUint(otf, to + 12, oLe);
108
+ otf.set(tab, toff);
109
+ toff += oLe;
110
+ }
111
+ return otf;
112
+ }
113
+ let data = buff instanceof Uint8Array ? buff : new Uint8Array(buff);
114
+ if (data[0] == 119) data = woffToOtf(data);
115
+ const tmap = {};
116
+ const tag = bin.readASCII(data, 0, 4);
117
+ if (tag == "ttcf") {
118
+ let offset = 4;
119
+ const majV = bin.readUshort(data, offset);
120
+ offset += 2;
121
+ const minV = bin.readUshort(data, offset);
122
+ offset += 2;
123
+ const numF = bin.readUint(data, offset);
124
+ offset += 4;
125
+ const fnts = [];
126
+ for (let i = 0; i < numF; i++) {
127
+ const foff = bin.readUint(data, offset);
128
+ offset += 4;
129
+ fnts.push(readFont(data, i, foff, tmap));
130
+ }
131
+ return fnts;
132
+ }
133
+ const fnt = readFont(data, 0, 0, tmap);
134
+ const fvar = fnt["fvar"];
135
+ if (fvar && fvar[1] && Array.isArray(fvar[1])) {
136
+ const out = [fnt];
137
+ for (let i = 0; i < fvar[1].length; i++) {
138
+ const fv = fvar[1][i];
139
+ const obj = {
140
+ _data: fnt._data,
141
+ _index: i,
142
+ _offset: fnt._offset
143
+ };
144
+ out.push(obj);
145
+ for (const p in fnt) obj[p] = fnt[p];
146
+ const name = obj["name"] = JSON.parse(JSON.stringify(obj["name"]));
147
+ name["fontSubfamily"] = fv[0];
148
+ }
149
+ return out;
150
+ }
151
+ return [fnt];
152
+ }
153
+ Typr2.parse = parse;
154
+ let B;
155
+ ((B2) => {
156
+ function readFixed(data, offset) {
157
+ const value = Typr2.B.readInt(data, offset);
158
+ return value / 65536;
159
+ }
160
+ B2.readFixed = readFixed;
161
+ function readF2dot14(data, offset) {
162
+ const num = Typr2.B.readShort(data, offset);
163
+ return num / 16384;
164
+ }
165
+ B2.readF2dot14 = readF2dot14;
166
+ function readInt(buff, offset) {
167
+ const a = Typr2.B.t.uint8;
168
+ a[0] = buff[offset + 3];
169
+ a[1] = buff[offset + 2];
170
+ a[2] = buff[offset + 1];
171
+ a[3] = buff[offset];
172
+ return Typr2.B.t.int32[0];
173
+ }
174
+ B2.readInt = readInt;
175
+ function readInt8(buff, offset) {
176
+ const a = Typr2.B.t.uint8;
177
+ a[0] = buff[offset];
178
+ return Typr2.B.t.int8[0];
179
+ }
180
+ B2.readInt8 = readInt8;
181
+ function readShort(buff, offset) {
182
+ const a = Typr2.B.t.uint16;
183
+ a[0] = buff[offset] << 8 | buff[offset + 1];
184
+ return Typr2.B.t.int16[0];
185
+ }
186
+ B2.readShort = readShort;
187
+ function readUshort(buff, offset) {
188
+ return buff[offset] << 8 | buff[offset + 1];
189
+ }
190
+ B2.readUshort = readUshort;
191
+ function writeUshort(buff, offset, value) {
192
+ buff[offset] = value >> 8 & 255;
193
+ buff[offset + 1] = value & 255;
194
+ }
195
+ B2.writeUshort = writeUshort;
196
+ function readUshorts(buff, offset, length) {
197
+ const arr = [];
198
+ for (let i = 0; i < length; i++) {
199
+ const v = Typr2.B.readUshort(buff, offset + i * 2);
200
+ arr.push(v);
201
+ }
202
+ return arr;
203
+ }
204
+ B2.readUshorts = readUshorts;
205
+ function readUint(buff, offset) {
206
+ const a = Typr2.B.t.uint8;
207
+ a[3] = buff[offset];
208
+ a[2] = buff[offset + 1];
209
+ a[1] = buff[offset + 2];
210
+ a[0] = buff[offset + 3];
211
+ return Typr2.B.t.uint32[0];
212
+ }
213
+ B2.readUint = readUint;
214
+ function writeUint(buff, offset, value) {
215
+ buff[offset] = value >> 24 & 255;
216
+ buff[offset + 1] = value >> 16 & 255;
217
+ buff[offset + 2] = value >> 8 & 255;
218
+ buff[offset + 3] = value >> 0 & 255;
219
+ }
220
+ B2.writeUint = writeUint;
221
+ function readUint64(buff, offset) {
222
+ return Typr2.B.readUint(buff, offset) * (4294967295 + 1) + Typr2.B.readUint(buff, offset + 4);
223
+ }
224
+ B2.readUint64 = readUint64;
225
+ function readASCII(buff, offset, length) {
226
+ let s = "";
227
+ for (let i = 0; i < length; i++)
228
+ s += String.fromCharCode(buff[offset + i]);
229
+ return s;
230
+ }
231
+ B2.readASCII = readASCII;
232
+ function writeASCII(buff, offset, str) {
233
+ for (let i = 0; i < str.length; i++) buff[offset + i] = str.charCodeAt(i);
234
+ }
235
+ B2.writeASCII = writeASCII;
236
+ function readUnicode(buff, offset, length) {
237
+ let s = "";
238
+ for (let i = 0; i < length; i++) {
239
+ const c = buff[offset++] << 8 | buff[offset++];
240
+ s += String.fromCharCode(c);
241
+ }
242
+ return s;
243
+ }
244
+ B2.readUnicode = readUnicode;
245
+ B2._tdec = typeof TextDecoder !== "undefined" ? new TextDecoder() : null;
246
+ function readUTF8(buff, offset, length) {
247
+ const tdec = Typr2.B._tdec;
248
+ if (tdec && offset == 0 && length == buff.length)
249
+ return tdec.decode(buff);
250
+ return Typr2.B.readASCII(buff, offset, length);
251
+ }
252
+ B2.readUTF8 = readUTF8;
253
+ function readBytes(buff, offset, length) {
254
+ const arr = [];
255
+ for (let i = 0; i < length; i++) arr.push(buff[offset + i]);
256
+ return arr;
257
+ }
258
+ B2.readBytes = readBytes;
259
+ function readASCIIArray(buff, offset, length) {
260
+ const s = [];
261
+ for (let i = 0; i < length; i++)
262
+ s.push(String.fromCharCode(buff[offset + i]));
263
+ return s;
264
+ }
265
+ B2.readASCIIArray = readASCIIArray;
266
+ B2.t = (function() {
267
+ const ab = new ArrayBuffer(8);
268
+ return {
269
+ buff: ab,
270
+ int8: new Int8Array(ab),
271
+ uint8: new Uint8Array(ab),
272
+ int16: new Int16Array(ab),
273
+ uint16: new Uint16Array(ab),
274
+ int32: new Int32Array(ab),
275
+ uint32: new Uint32Array(ab)
276
+ };
277
+ })();
278
+ })(B = Typr2.B || (Typr2.B = {}));
279
+ let T;
280
+ ((T2) => {
281
+ T2.CFF = {
282
+ parseTab: function(data, offset, length) {
283
+ const bin = Typr2.B;
284
+ const CFF2 = Typr2.T.CFF;
285
+ data = new Uint8Array(data.buffer, offset, length);
286
+ offset = 0;
287
+ const major = data[offset];
288
+ offset++;
289
+ const minor = data[offset];
290
+ offset++;
291
+ const hdrSize = data[offset];
292
+ offset++;
293
+ const offsize = data[offset];
294
+ offset++;
295
+ const ninds = [];
296
+ offset = CFF2.readIndex(data, offset, ninds);
297
+ const names = [];
298
+ for (let i = 0; i < ninds.length - 1; i++)
299
+ names.push(
300
+ bin.readASCII(data, offset + ninds[i], ninds[i + 1] - ninds[i])
301
+ );
302
+ offset += ninds[ninds.length - 1];
303
+ const tdinds = [];
304
+ offset = CFF2.readIndex(data, offset, tdinds);
305
+ const topDicts = [];
306
+ for (let i = 0; i < tdinds.length - 1; i++)
307
+ topDicts.push(
308
+ CFF2.readDict(data, offset + tdinds[i], offset + tdinds[i + 1])
309
+ );
310
+ offset += tdinds[tdinds.length - 1];
311
+ const topdict = topDicts[0];
312
+ const sinds = [];
313
+ offset = CFF2.readIndex(data, offset, sinds);
314
+ const strings = [];
315
+ for (let i = 0; i < sinds.length - 1; i++)
316
+ strings.push(
317
+ bin.readASCII(data, offset + sinds[i], sinds[i + 1] - sinds[i])
318
+ );
319
+ offset += sinds[sinds.length - 1];
320
+ CFF2.readSubrs(data, offset, topdict);
321
+ if (topdict["CharStrings"])
322
+ topdict["CharStrings"] = CFF2.readBytes(data, topdict["CharStrings"]);
323
+ if (topdict["ROS"]) {
324
+ offset = topdict["FDArray"];
325
+ const fdind = [];
326
+ offset = CFF2.readIndex(data, offset, fdind);
327
+ topdict["FDArray"] = [];
328
+ for (let i = 0; i < fdind.length - 1; i++) {
329
+ const dict = CFF2.readDict(
330
+ data,
331
+ offset + fdind[i],
332
+ offset + fdind[i + 1]
333
+ );
334
+ CFF2._readFDict(data, dict, strings);
335
+ topdict["FDArray"].push(dict);
336
+ }
337
+ offset += fdind[fdind.length - 1];
338
+ offset = topdict["FDSelect"];
339
+ topdict["FDSelect"] = [];
340
+ const fmt = data[offset];
341
+ offset++;
342
+ if (fmt == 3) {
343
+ const rns = bin.readUshort(data, offset);
344
+ offset += 2;
345
+ for (let i = 0; i < rns + 1; i++) {
346
+ topdict["FDSelect"].push(
347
+ bin.readUshort(data, offset),
348
+ data[offset + 2]
349
+ );
350
+ offset += 3;
351
+ }
352
+ } else throw new Error(`Unknown format: ${fmt}`);
353
+ }
354
+ if (topdict["charset"] && topdict["CharStrings"])
355
+ topdict["charset"] = CFF2.readCharset(
356
+ data,
357
+ topdict["charset"],
358
+ topdict["CharStrings"].length
359
+ );
360
+ CFF2._readFDict(data, topdict, strings);
361
+ return topdict;
362
+ },
363
+ _readFDict: function(data, dict, ss) {
364
+ const CFF2 = Typr2.T.CFF;
365
+ let offset;
366
+ if (dict["Private"]) {
367
+ offset = dict["Private"][1];
368
+ dict["Private"] = CFF2.readDict(
369
+ data,
370
+ offset,
371
+ offset + dict["Private"][0]
372
+ );
373
+ if (dict["Private"]["Subrs"])
374
+ CFF2.readSubrs(
375
+ data,
376
+ offset + dict["Private"]["Subrs"],
377
+ dict["Private"]
378
+ );
379
+ }
380
+ for (const p in dict)
381
+ if ([
382
+ "FamilyName",
383
+ "FontName",
384
+ "FullName",
385
+ "Notice",
386
+ "version",
387
+ "Copyright"
388
+ ].indexOf(p) != -1)
389
+ dict[p] = ss[dict[p] - 426 + 35];
390
+ },
391
+ readSubrs: function(data, offset, obj) {
392
+ obj["Subrs"] = Typr2.T.CFF.readBytes(data, offset);
393
+ let bias;
394
+ const nSubrs = obj["Subrs"].length + 1;
395
+ if (false) bias = 0;
396
+ else if (nSubrs < 1240) bias = 107;
397
+ else if (nSubrs < 33900) bias = 1131;
398
+ else bias = 32768;
399
+ obj["Bias"] = bias;
400
+ },
401
+ readBytes: function(data, offset) {
402
+ const bin = Typr2.B;
403
+ const arr = [];
404
+ offset = Typr2.T.CFF.readIndex(data, offset, arr);
405
+ const subrs = [];
406
+ const arl = arr.length - 1;
407
+ const no = data.byteOffset + offset;
408
+ for (let i = 0; i < arl; i++) {
409
+ const ari = arr[i];
410
+ subrs.push(
411
+ new Uint8Array(
412
+ data.buffer,
413
+ no + ari,
414
+ arr[i + 1] - ari
415
+ )
416
+ );
417
+ }
418
+ return subrs;
419
+ },
420
+ tableSE: [
421
+ 0,
422
+ 0,
423
+ 0,
424
+ 0,
425
+ 0,
426
+ 0,
427
+ 0,
428
+ 0,
429
+ 0,
430
+ 0,
431
+ 0,
432
+ 0,
433
+ 0,
434
+ 0,
435
+ 0,
436
+ 0,
437
+ 0,
438
+ 0,
439
+ 0,
440
+ 0,
441
+ 0,
442
+ 0,
443
+ 0,
444
+ 0,
445
+ 0,
446
+ 0,
447
+ 0,
448
+ 0,
449
+ 0,
450
+ 0,
451
+ 0,
452
+ 0,
453
+ 1,
454
+ 2,
455
+ 3,
456
+ 4,
457
+ 5,
458
+ 6,
459
+ 7,
460
+ 8,
461
+ 9,
462
+ 10,
463
+ 11,
464
+ 12,
465
+ 13,
466
+ 14,
467
+ 15,
468
+ 16,
469
+ 17,
470
+ 18,
471
+ 19,
472
+ 20,
473
+ 21,
474
+ 22,
475
+ 23,
476
+ 24,
477
+ 25,
478
+ 26,
479
+ 27,
480
+ 28,
481
+ 29,
482
+ 30,
483
+ 31,
484
+ 32,
485
+ 33,
486
+ 34,
487
+ 35,
488
+ 36,
489
+ 37,
490
+ 38,
491
+ 39,
492
+ 40,
493
+ 41,
494
+ 42,
495
+ 43,
496
+ 44,
497
+ 45,
498
+ 46,
499
+ 47,
500
+ 48,
501
+ 49,
502
+ 50,
503
+ 51,
504
+ 52,
505
+ 53,
506
+ 54,
507
+ 55,
508
+ 56,
509
+ 57,
510
+ 58,
511
+ 59,
512
+ 60,
513
+ 61,
514
+ 62,
515
+ 63,
516
+ 64,
517
+ 65,
518
+ 66,
519
+ 67,
520
+ 68,
521
+ 69,
522
+ 70,
523
+ 71,
524
+ 72,
525
+ 73,
526
+ 74,
527
+ 75,
528
+ 76,
529
+ 77,
530
+ 78,
531
+ 79,
532
+ 80,
533
+ 81,
534
+ 82,
535
+ 83,
536
+ 84,
537
+ 85,
538
+ 86,
539
+ 87,
540
+ 88,
541
+ 89,
542
+ 90,
543
+ 91,
544
+ 92,
545
+ 93,
546
+ 94,
547
+ 95,
548
+ 0,
549
+ 0,
550
+ 0,
551
+ 0,
552
+ 0,
553
+ 0,
554
+ 0,
555
+ 0,
556
+ 0,
557
+ 0,
558
+ 0,
559
+ 0,
560
+ 0,
561
+ 0,
562
+ 0,
563
+ 0,
564
+ 0,
565
+ 0,
566
+ 0,
567
+ 0,
568
+ 0,
569
+ 0,
570
+ 0,
571
+ 0,
572
+ 0,
573
+ 0,
574
+ 0,
575
+ 0,
576
+ 0,
577
+ 0,
578
+ 0,
579
+ 0,
580
+ 0,
581
+ 0,
582
+ 96,
583
+ 97,
584
+ 98,
585
+ 99,
586
+ 100,
587
+ 101,
588
+ 102,
589
+ 103,
590
+ 104,
591
+ 105,
592
+ 106,
593
+ 107,
594
+ 108,
595
+ 109,
596
+ 110,
597
+ 0,
598
+ 111,
599
+ 112,
600
+ 113,
601
+ 114,
602
+ 0,
603
+ 115,
604
+ 116,
605
+ 117,
606
+ 118,
607
+ 119,
608
+ 120,
609
+ 121,
610
+ 122,
611
+ 0,
612
+ 123,
613
+ 0,
614
+ 124,
615
+ 125,
616
+ 126,
617
+ 127,
618
+ 128,
619
+ 129,
620
+ 130,
621
+ 131,
622
+ 0,
623
+ 132,
624
+ 133,
625
+ 0,
626
+ 134,
627
+ 135,
628
+ 136,
629
+ 137,
630
+ 0,
631
+ 0,
632
+ 0,
633
+ 0,
634
+ 0,
635
+ 0,
636
+ 0,
637
+ 0,
638
+ 0,
639
+ 0,
640
+ 0,
641
+ 0,
642
+ 0,
643
+ 0,
644
+ 0,
645
+ 0,
646
+ 138,
647
+ 0,
648
+ 139,
649
+ 0,
650
+ 0,
651
+ 0,
652
+ 0,
653
+ 140,
654
+ 141,
655
+ 142,
656
+ 143,
657
+ 0,
658
+ 0,
659
+ 0,
660
+ 0,
661
+ 0,
662
+ 144,
663
+ 0,
664
+ 0,
665
+ 0,
666
+ 145,
667
+ 0,
668
+ 0,
669
+ 146,
670
+ 147,
671
+ 148,
672
+ 149,
673
+ 0,
674
+ 0,
675
+ 0,
676
+ 0
677
+ ],
678
+ glyphByUnicode: function(cff, code) {
679
+ if (!cff["charset"]) return -1;
680
+ for (let i = 0; i < cff["charset"].length; i++)
681
+ if (cff["charset"][i] == code) return i;
682
+ return -1;
683
+ },
684
+ glyphBySE: function(cff, charcode) {
685
+ if (charcode < 0 || charcode > 255) return -1;
686
+ return Typr2.T.CFF.glyphByUnicode(cff, Typr2.T.CFF.tableSE[charcode]);
687
+ },
688
+ readCharset: function(data, offset, num) {
689
+ const bin = Typr2.B;
690
+ const charset = [0];
691
+ const format = data[offset];
692
+ offset++;
693
+ if (format == 0) {
694
+ for (let i = 0; i < num; i++) {
695
+ const first = bin.readUshort(data, offset);
696
+ offset += 2;
697
+ charset.push(first);
698
+ }
699
+ } else if (format == 1 || format == 2) {
700
+ while (charset.length < num) {
701
+ let first = bin.readUshort(data, offset);
702
+ offset += 2;
703
+ let nLeft = 0;
704
+ if (format == 1) {
705
+ nLeft = data[offset];
706
+ offset++;
707
+ } else {
708
+ nLeft = bin.readUshort(data, offset);
709
+ offset += 2;
710
+ }
711
+ for (let i = 0; i <= nLeft; i++) {
712
+ charset.push(first);
713
+ first++;
714
+ }
715
+ }
716
+ } else throw new Error(`Unknown format: ${format}`);
717
+ return charset;
718
+ },
719
+ readIndex: function(data, offset, inds) {
720
+ const bin = Typr2.B;
721
+ const count = bin.readUshort(data, offset) + 1;
722
+ offset += 2;
723
+ const offsize = data[offset];
724
+ offset++;
725
+ if (offsize == 1)
726
+ for (let i = 0; i < count; i++) inds.push(data[offset + i]);
727
+ else if (offsize == 2)
728
+ for (let i = 0; i < count; i++)
729
+ inds.push(bin.readUshort(data, offset + i * 2));
730
+ else if (offsize == 3)
731
+ for (let i = 0; i < count; i++)
732
+ inds.push(bin.readUint(data, offset + i * 3 - 1) & 16777215);
733
+ else if (offsize == 4)
734
+ for (let i = 0; i < count; i++)
735
+ inds.push(bin.readUint(data, offset + i * 4));
736
+ else if (count != 1)
737
+ throw new Error(
738
+ `Unsupported offset size: ${offsize}, count: ${count}`
739
+ );
740
+ offset += count * offsize;
741
+ return offset - 1;
742
+ },
743
+ getCharString: function(data, offset, o) {
744
+ const bin = Typr2.B;
745
+ const b0 = data[offset];
746
+ const b1 = data[offset + 1];
747
+ const b2 = data[offset + 2];
748
+ const b3 = data[offset + 3];
749
+ const b4 = data[offset + 4];
750
+ let vs = 1;
751
+ let op = null;
752
+ let val = null;
753
+ if (b0 <= 20) {
754
+ op = b0;
755
+ vs = 1;
756
+ }
757
+ if (b0 == 12) {
758
+ op = b0 * 100 + b1;
759
+ vs = 2;
760
+ }
761
+ if (21 <= b0 && b0 <= 27) {
762
+ op = b0;
763
+ vs = 1;
764
+ }
765
+ if (b0 == 28) {
766
+ val = bin.readShort(data, offset + 1);
767
+ vs = 3;
768
+ }
769
+ if (29 <= b0 && b0 <= 31) {
770
+ op = b0;
771
+ vs = 1;
772
+ }
773
+ if (32 <= b0 && b0 <= 246) {
774
+ val = b0 - 139;
775
+ vs = 1;
776
+ }
777
+ if (247 <= b0 && b0 <= 250) {
778
+ val = (b0 - 247) * 256 + b1 + 108;
779
+ vs = 2;
780
+ }
781
+ if (251 <= b0 && b0 <= 254) {
782
+ val = -(b0 - 251) * 256 - b1 - 108;
783
+ vs = 2;
784
+ }
785
+ if (b0 == 255) {
786
+ val = bin.readInt(data, offset + 1) / 65535;
787
+ vs = 5;
788
+ }
789
+ o.val = val != null ? val : "o" + op;
790
+ o.size = vs;
791
+ },
792
+ readCharString: function(data, offset, length) {
793
+ const end = offset + length;
794
+ const bin = Typr2.B;
795
+ const arr = [];
796
+ while (offset < end) {
797
+ const b0 = data[offset];
798
+ const b1 = data[offset + 1];
799
+ const b2 = data[offset + 2];
800
+ const b3 = data[offset + 3];
801
+ const b4 = data[offset + 4];
802
+ let vs = 1;
803
+ let op = null;
804
+ let val = null;
805
+ if (b0 <= 20) {
806
+ op = b0;
807
+ vs = 1;
808
+ }
809
+ if (b0 == 12) {
810
+ op = b0 * 100 + b1;
811
+ vs = 2;
812
+ }
813
+ if (b0 == 19 || b0 == 20) {
814
+ op = b0;
815
+ vs = 2;
816
+ }
817
+ if (21 <= b0 && b0 <= 27) {
818
+ op = b0;
819
+ vs = 1;
820
+ }
821
+ if (b0 == 28) {
822
+ val = bin.readShort(data, offset + 1);
823
+ vs = 3;
824
+ }
825
+ if (29 <= b0 && b0 <= 31) {
826
+ op = b0;
827
+ vs = 1;
828
+ }
829
+ if (32 <= b0 && b0 <= 246) {
830
+ val = b0 - 139;
831
+ vs = 1;
832
+ }
833
+ if (247 <= b0 && b0 <= 250) {
834
+ val = (b0 - 247) * 256 + b1 + 108;
835
+ vs = 2;
836
+ }
837
+ if (251 <= b0 && b0 <= 254) {
838
+ val = -(b0 - 251) * 256 - b1 - 108;
839
+ vs = 2;
840
+ }
841
+ if (b0 == 255) {
842
+ val = bin.readInt(data, offset + 1) / 65535;
843
+ vs = 5;
844
+ }
845
+ arr.push(val != null ? val : "o" + op);
846
+ offset += vs;
847
+ }
848
+ return arr;
849
+ },
850
+ readDict: function(data, offset, end) {
851
+ const bin = Typr2.B;
852
+ const dict = {};
853
+ const carr = [];
854
+ while (offset < end) {
855
+ const b0 = data[offset];
856
+ const b1 = data[offset + 1];
857
+ const b2 = data[offset + 2];
858
+ const b3 = data[offset + 3];
859
+ const b4 = data[offset + 4];
860
+ let vs = 1;
861
+ let key = null;
862
+ let val = null;
863
+ if (b0 == 28) {
864
+ val = bin.readShort(data, offset + 1);
865
+ vs = 3;
866
+ }
867
+ if (b0 == 29) {
868
+ val = bin.readInt(data, offset + 1);
869
+ vs = 5;
870
+ }
871
+ if (32 <= b0 && b0 <= 246) {
872
+ val = b0 - 139;
873
+ vs = 1;
874
+ }
875
+ if (247 <= b0 && b0 <= 250) {
876
+ val = (b0 - 247) * 256 + b1 + 108;
877
+ vs = 2;
878
+ }
879
+ if (251 <= b0 && b0 <= 254) {
880
+ val = -(b0 - 251) * 256 - b1 - 108;
881
+ vs = 2;
882
+ }
883
+ if (b0 == 255) {
884
+ val = bin.readInt(data, offset + 1) / 65535;
885
+ vs = 5;
886
+ throw new Error("Unknown number");
887
+ }
888
+ if (b0 == 30) {
889
+ const nibs = [];
890
+ vs = 1;
891
+ while (true) {
892
+ const b = data[offset + vs];
893
+ vs++;
894
+ const nib0 = b >> 4;
895
+ const nib1 = b & 15;
896
+ if (nib0 != 15) nibs.push(nib0);
897
+ if (nib1 != 15) nibs.push(nib1);
898
+ if (nib1 == 15) break;
899
+ }
900
+ let s = "";
901
+ const chars = [
902
+ 0,
903
+ 1,
904
+ 2,
905
+ 3,
906
+ 4,
907
+ 5,
908
+ 6,
909
+ 7,
910
+ 8,
911
+ 9,
912
+ ".",
913
+ "e",
914
+ "e-",
915
+ "reserved",
916
+ "-",
917
+ "endOfNumber"
918
+ ];
919
+ for (let i = 0; i < nibs.length; i++) s += chars[nibs[i]];
920
+ val = parseFloat(s);
921
+ }
922
+ if (b0 <= 21) {
923
+ const keys = [
924
+ "version",
925
+ "Notice",
926
+ "FullName",
927
+ "FamilyName",
928
+ "Weight",
929
+ "FontBBox",
930
+ "BlueValues",
931
+ "OtherBlues",
932
+ "FamilyBlues",
933
+ "FamilyOtherBlues",
934
+ "StdHW",
935
+ "StdVW",
936
+ "escape",
937
+ "UniqueID",
938
+ "XUID",
939
+ "charset",
940
+ "Encoding",
941
+ "CharStrings",
942
+ "Private",
943
+ "Subrs",
944
+ "defaultWidthX",
945
+ "nominalWidthX"
946
+ ];
947
+ key = keys[b0];
948
+ vs = 1;
949
+ if (b0 == 12) {
950
+ const keys2 = [
951
+ "Copyright",
952
+ "isFixedPitch",
953
+ "ItalicAngle",
954
+ "UnderlinePosition",
955
+ "UnderlineThickness",
956
+ "PaintType",
957
+ "CharstringType",
958
+ "FontMatrix",
959
+ "StrokeWidth",
960
+ "BlueScale",
961
+ "BlueShift",
962
+ "BlueFuzz",
963
+ "StemSnapH",
964
+ "StemSnapV",
965
+ "ForceBold",
966
+ "",
967
+ "",
968
+ "LanguageGroup",
969
+ "ExpansionFactor",
970
+ "initialRandomSeed",
971
+ "SyntheticBase",
972
+ "PostScript",
973
+ "BaseFontName",
974
+ "BaseFontBlend",
975
+ "",
976
+ "",
977
+ "",
978
+ "",
979
+ "",
980
+ "",
981
+ "ROS",
982
+ "CIDFontVersion",
983
+ "CIDFontRevision",
984
+ "CIDFontType",
985
+ "CIDCount",
986
+ "UIDBase",
987
+ "FDArray",
988
+ "FDSelect",
989
+ "FontName"
990
+ ];
991
+ key = keys2[b1];
992
+ vs = 2;
993
+ }
994
+ }
995
+ if (key != null) {
996
+ dict[key] = carr.length == 1 ? carr[0] : carr;
997
+ carr.length = 0;
998
+ } else carr.push(val);
999
+ offset += vs;
1000
+ }
1001
+ return dict;
1002
+ }
1003
+ };
1004
+ T2.cmap = {
1005
+ parseTab: function(data, offset, length) {
1006
+ const obj = { tables: [], ids: {}, off: offset };
1007
+ data = new Uint8Array(data.buffer, offset, length);
1008
+ offset = 0;
1009
+ const offset0 = offset;
1010
+ const bin = Typr2.B;
1011
+ const rU = bin.readUshort;
1012
+ const cmap2 = Typr2.T.cmap;
1013
+ const version = rU(data, offset);
1014
+ offset += 2;
1015
+ const numTables = rU(data, offset);
1016
+ offset += 2;
1017
+ const offs = [];
1018
+ for (let i = 0; i < numTables; i++) {
1019
+ const platformID = rU(data, offset);
1020
+ offset += 2;
1021
+ const encodingID = rU(data, offset);
1022
+ offset += 2;
1023
+ const noffset = bin.readUint(data, offset);
1024
+ offset += 4;
1025
+ const id = "p" + platformID + "e" + encodingID;
1026
+ const tind = offs.indexOf(noffset);
1027
+ if (tind == -1) {
1028
+ const tind2 = obj.tables.length;
1029
+ const subt = { format: 0 };
1030
+ offs.push(noffset);
1031
+ const format = subt.format = rU(data, noffset);
1032
+ if (format == 0)
1033
+ Object.assign(subt, cmap2.parse0(data, noffset, subt));
1034
+ else if (format == 4)
1035
+ Object.assign(subt, cmap2.parse4(data, noffset, subt));
1036
+ else if (format == 6)
1037
+ Object.assign(subt, cmap2.parse6(data, noffset, subt));
1038
+ else if (format == 12)
1039
+ Object.assign(subt, cmap2.parse12(data, noffset, subt));
1040
+ obj.tables.push(subt);
1041
+ }
1042
+ if (obj.ids[id] != null)
1043
+ console.log("multiple tables for one platform+encoding: " + id);
1044
+ obj.ids[id] = tind;
1045
+ }
1046
+ return obj;
1047
+ },
1048
+ parse0: function(data, offset, obj) {
1049
+ const bin = Typr2.B;
1050
+ offset += 2;
1051
+ const len = bin.readUshort(data, offset);
1052
+ offset += 2;
1053
+ const lang = bin.readUshort(data, offset);
1054
+ offset += 2;
1055
+ obj.map = [];
1056
+ for (let i = 0; i < len - 6; i++) obj.map.push(data[offset + i]);
1057
+ return obj;
1058
+ },
1059
+ parse4: function(data, offset, obj) {
1060
+ const bin = Typr2.B;
1061
+ const rU = bin.readUshort;
1062
+ const rUs = bin.readUshorts;
1063
+ const offset0 = offset;
1064
+ offset += 2;
1065
+ const length = rU(data, offset);
1066
+ offset += 2;
1067
+ const language = rU(data, offset);
1068
+ offset += 2;
1069
+ const segCountX2 = rU(data, offset);
1070
+ offset += 2;
1071
+ const segCount = segCountX2 >>> 1;
1072
+ obj.searchRange = rU(data, offset);
1073
+ offset += 2;
1074
+ obj.entrySelector = rU(data, offset);
1075
+ offset += 2;
1076
+ obj.rangeShift = rU(data, offset);
1077
+ offset += 2;
1078
+ obj.endCount = rUs(data, offset, segCount);
1079
+ offset += segCount * 2;
1080
+ offset += 2;
1081
+ obj.startCount = rUs(data, offset, segCount);
1082
+ offset += segCount * 2;
1083
+ obj.idDelta = [];
1084
+ for (let i = 0; i < segCount; i++) {
1085
+ obj.idDelta.push(bin.readShort(data, offset));
1086
+ offset += 2;
1087
+ }
1088
+ obj.idRangeOffset = rUs(data, offset, segCount);
1089
+ offset += segCount * 2;
1090
+ obj.glyphIdArray = rUs(data, offset, offset0 + length - offset >> 1);
1091
+ return obj;
1092
+ },
1093
+ parse6: function(data, offset, obj) {
1094
+ const bin = Typr2.B;
1095
+ const offset0 = offset;
1096
+ offset += 2;
1097
+ const length = bin.readUshort(data, offset);
1098
+ offset += 2;
1099
+ const language = bin.readUshort(data, offset);
1100
+ offset += 2;
1101
+ obj.firstCode = bin.readUshort(data, offset);
1102
+ offset += 2;
1103
+ const entryCount = bin.readUshort(data, offset);
1104
+ offset += 2;
1105
+ obj.glyphIdArray = [];
1106
+ for (let i = 0; i < entryCount; i++) {
1107
+ obj.glyphIdArray.push(bin.readUshort(data, offset));
1108
+ offset += 2;
1109
+ }
1110
+ return obj;
1111
+ },
1112
+ parse12: function(data, offset, obj) {
1113
+ const bin = Typr2.B;
1114
+ const rU = bin.readUint;
1115
+ const offset0 = offset;
1116
+ offset += 4;
1117
+ const length = rU(data, offset);
1118
+ offset += 4;
1119
+ const lang = rU(data, offset);
1120
+ offset += 4;
1121
+ const nGroups = rU(data, offset) * 3;
1122
+ offset += 4;
1123
+ const gps = obj.groups = new Uint32Array(nGroups);
1124
+ for (let i = 0; i < nGroups; i += 3) {
1125
+ gps[i] = rU(data, offset + (i << 2));
1126
+ gps[i + 1] = rU(data, offset + (i << 2) + 4);
1127
+ gps[i + 2] = rU(data, offset + (i << 2) + 8);
1128
+ }
1129
+ return obj;
1130
+ }
1131
+ };
1132
+ T2.head = {
1133
+ parseTab: function(data, offset, length) {
1134
+ const bin = Typr2.B;
1135
+ const obj = {};
1136
+ const tableVersion = bin.readFixed(data, offset);
1137
+ offset += 4;
1138
+ obj.fontRevision = bin.readFixed(data, offset);
1139
+ offset += 4;
1140
+ const checkSumAdjustment = bin.readUint(data, offset);
1141
+ offset += 4;
1142
+ const magicNumber = bin.readUint(data, offset);
1143
+ offset += 4;
1144
+ obj.flags = bin.readUshort(data, offset);
1145
+ offset += 2;
1146
+ obj.unitsPerEm = bin.readUshort(data, offset);
1147
+ offset += 2;
1148
+ obj.created = bin.readUint64(data, offset);
1149
+ offset += 8;
1150
+ obj.modified = bin.readUint64(data, offset);
1151
+ offset += 8;
1152
+ obj.xMin = bin.readShort(data, offset);
1153
+ offset += 2;
1154
+ obj.yMin = bin.readShort(data, offset);
1155
+ offset += 2;
1156
+ obj.xMax = bin.readShort(data, offset);
1157
+ offset += 2;
1158
+ obj.yMax = bin.readShort(data, offset);
1159
+ offset += 2;
1160
+ obj.macStyle = bin.readUshort(data, offset);
1161
+ offset += 2;
1162
+ obj.lowestRecPPEM = bin.readUshort(data, offset);
1163
+ offset += 2;
1164
+ obj.fontDirectionHint = bin.readShort(data, offset);
1165
+ offset += 2;
1166
+ obj.indexToLocFormat = bin.readShort(data, offset);
1167
+ offset += 2;
1168
+ obj.glyphDataFormat = bin.readShort(data, offset);
1169
+ offset += 2;
1170
+ return obj;
1171
+ }
1172
+ };
1173
+ T2.hhea = {
1174
+ parseTab: function(data, offset, length) {
1175
+ const bin = Typr2.B;
1176
+ const obj = {};
1177
+ const tableVersion = bin.readFixed(data, offset);
1178
+ offset += 4;
1179
+ const keys = [
1180
+ "ascender",
1181
+ "descender",
1182
+ "lineGap",
1183
+ "advanceWidthMax",
1184
+ "minLeftSideBearing",
1185
+ "minRightSideBearing",
1186
+ "xMaxExtent",
1187
+ "caretSlopeRise",
1188
+ "caretSlopeRun",
1189
+ "caretOffset",
1190
+ "res0",
1191
+ "res1",
1192
+ "res2",
1193
+ "res3",
1194
+ "metricDataFormat",
1195
+ "numberOfHMetrics"
1196
+ ];
1197
+ for (let i = 0; i < keys.length; i++) {
1198
+ const key = keys[i];
1199
+ const func = key == "advanceWidthMax" || key == "numberOfHMetrics" ? bin.readUshort : bin.readShort;
1200
+ obj[key] = func(data, offset + i * 2);
1201
+ }
1202
+ return obj;
1203
+ }
1204
+ };
1205
+ T2.maxp = {
1206
+ parseTab: function(data, offset, length) {
1207
+ const bin = Typr2.B;
1208
+ const obj = {};
1209
+ const ver = bin.readUint(data, offset);
1210
+ offset += 4;
1211
+ obj.numGlyphs = bin.readUshort(data, offset);
1212
+ offset += 2;
1213
+ return obj;
1214
+ }
1215
+ };
1216
+ T2.hmtx = {
1217
+ parseTab: function(data, offset, length, font) {
1218
+ const bin = Typr2.B;
1219
+ const aWidth = [];
1220
+ const lsBearing = [];
1221
+ const nG = font["maxp"]?.["numGlyphs"] || 0;
1222
+ const nH = font["hhea"]?.["numberOfHMetrics"] || 0;
1223
+ let aw = 0, lsb = 0, i = 0;
1224
+ while (i < nH) {
1225
+ aw = bin.readUshort(data, offset + (i << 2));
1226
+ lsb = bin.readShort(data, offset + (i << 2) + 2);
1227
+ aWidth.push(aw);
1228
+ lsBearing.push(lsb);
1229
+ i++;
1230
+ }
1231
+ while (i < nG) {
1232
+ aWidth.push(aw);
1233
+ lsBearing.push(lsb);
1234
+ i++;
1235
+ }
1236
+ return { aWidth, lsBearing };
1237
+ }
1238
+ };
1239
+ T2.loca = {
1240
+ parseTab: function(data, offset, length, font) {
1241
+ const bin = Typr2.B;
1242
+ const obj = [];
1243
+ const ver = font["head"]?.["indexToLocFormat"] || 0;
1244
+ const len = (font["maxp"]?.["numGlyphs"] || 0) + 1;
1245
+ if (ver == 0)
1246
+ for (let i = 0; i < len; i++)
1247
+ obj.push(bin.readUshort(data, offset + (i << 1)) << 1);
1248
+ if (ver == 1)
1249
+ for (let i = 0; i < len; i++)
1250
+ obj.push(bin.readUint(data, offset + (i << 2)));
1251
+ return obj;
1252
+ }
1253
+ };
1254
+ T2.glyf = {
1255
+ parseTab: function(data, offset, length, font) {
1256
+ const obj = [];
1257
+ const ng = font["maxp"]?.["numGlyphs"] || 0;
1258
+ for (let g = 0; g < ng; g++) obj.push(null);
1259
+ return obj;
1260
+ },
1261
+ _parseGlyf: function(font, g) {
1262
+ const bin = Typr2.B;
1263
+ const data = font["_data"];
1264
+ const loca2 = font["loca"];
1265
+ if (!loca2) return null;
1266
+ if (loca2[g] == loca2[g + 1]) return null;
1267
+ const tableInfo = Typr2.findTable(data, "glyf", font["_offset"]);
1268
+ if (!tableInfo) return null;
1269
+ const offset = tableInfo[0] + loca2[g];
1270
+ const gl = {};
1271
+ gl.noc = bin.readShort(data, offset);
1272
+ let currentOffset = offset + 2;
1273
+ gl.xMin = bin.readShort(data, currentOffset);
1274
+ currentOffset += 2;
1275
+ gl.yMin = bin.readShort(data, currentOffset);
1276
+ currentOffset += 2;
1277
+ gl.xMax = bin.readShort(data, currentOffset);
1278
+ currentOffset += 2;
1279
+ gl.yMax = bin.readShort(data, currentOffset);
1280
+ currentOffset += 2;
1281
+ if (gl.xMin >= gl.xMax || gl.yMin >= gl.yMax) return null;
1282
+ if (gl.noc > 0) {
1283
+ gl.endPts = [];
1284
+ for (let i = 0; i < gl.noc; i++) {
1285
+ gl.endPts.push(bin.readUshort(data, currentOffset));
1286
+ currentOffset += 2;
1287
+ }
1288
+ const instructionLength = bin.readUshort(data, currentOffset);
1289
+ currentOffset += 2;
1290
+ if (data.length - currentOffset < instructionLength) return null;
1291
+ gl.instructions = bin.readBytes(
1292
+ data,
1293
+ currentOffset,
1294
+ instructionLength
1295
+ );
1296
+ currentOffset += instructionLength;
1297
+ const crdnum = gl.endPts[gl.noc - 1] + 1;
1298
+ gl.flags = [];
1299
+ for (let i = 0; i < crdnum; i++) {
1300
+ const flag = data[currentOffset];
1301
+ currentOffset++;
1302
+ gl.flags.push(flag);
1303
+ if ((flag & 8) != 0) {
1304
+ const rep = data[currentOffset];
1305
+ currentOffset++;
1306
+ for (let j = 0; j < rep; j++) {
1307
+ gl.flags.push(flag);
1308
+ i++;
1309
+ }
1310
+ }
1311
+ }
1312
+ gl.xs = [];
1313
+ for (let i = 0; i < crdnum; i++) {
1314
+ const i8 = (gl.flags[i] & 2) != 0;
1315
+ const same = (gl.flags[i] & 16) != 0;
1316
+ if (i8) {
1317
+ gl.xs.push(same ? data[currentOffset] : -data[currentOffset]);
1318
+ currentOffset++;
1319
+ } else {
1320
+ if (same) gl.xs.push(0);
1321
+ else {
1322
+ gl.xs.push(bin.readShort(data, currentOffset));
1323
+ currentOffset += 2;
1324
+ }
1325
+ }
1326
+ }
1327
+ gl.ys = [];
1328
+ for (let i = 0; i < crdnum; i++) {
1329
+ const i8 = (gl.flags[i] & 4) != 0;
1330
+ const same = (gl.flags[i] & 32) != 0;
1331
+ if (i8) {
1332
+ gl.ys.push(same ? data[currentOffset] : -data[currentOffset]);
1333
+ currentOffset++;
1334
+ } else {
1335
+ if (same) gl.ys.push(0);
1336
+ else {
1337
+ gl.ys.push(bin.readShort(data, currentOffset));
1338
+ currentOffset += 2;
1339
+ }
1340
+ }
1341
+ }
1342
+ let x = 0;
1343
+ let y = 0;
1344
+ for (let i = 0; i < crdnum; i++) {
1345
+ x += gl.xs[i];
1346
+ y += gl.ys[i];
1347
+ gl.xs[i] = x;
1348
+ gl.ys[i] = y;
1349
+ }
1350
+ } else {
1351
+ const ARG_1_AND_2_ARE_WORDS = 1 << 0;
1352
+ const ARGS_ARE_XY_VALUES = 1 << 1;
1353
+ const ROUND_XY_TO_GRID = 1 << 2;
1354
+ const WE_HAVE_A_SCALE = 1 << 3;
1355
+ const RESERVED = 1 << 4;
1356
+ const MORE_COMPONENTS = 1 << 5;
1357
+ const WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
1358
+ const WE_HAVE_A_TWO_BY_TWO = 1 << 7;
1359
+ const WE_HAVE_INSTRUCTIONS = 1 << 8;
1360
+ const USE_MY_METRICS = 1 << 9;
1361
+ const OVERLAP_COMPOUND = 1 << 10;
1362
+ const SCALED_COMPONENT_OFFSET = 1 << 11;
1363
+ const UNSCALED_COMPONENT_OFFSET = 1 << 12;
1364
+ gl.parts = [];
1365
+ let flags;
1366
+ do {
1367
+ flags = bin.readUshort(data, currentOffset);
1368
+ currentOffset += 2;
1369
+ const part = {
1370
+ m: { a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 },
1371
+ p1: -1,
1372
+ p2: -1
1373
+ };
1374
+ gl.parts.push(part);
1375
+ part.glyphIndex = bin.readUshort(data, currentOffset);
1376
+ currentOffset += 2;
1377
+ let arg1, arg2;
1378
+ if (flags & ARG_1_AND_2_ARE_WORDS) {
1379
+ arg1 = bin.readShort(data, currentOffset);
1380
+ currentOffset += 2;
1381
+ arg2 = bin.readShort(data, currentOffset);
1382
+ currentOffset += 2;
1383
+ } else {
1384
+ arg1 = bin.readInt8(data, currentOffset);
1385
+ currentOffset++;
1386
+ arg2 = bin.readInt8(data, currentOffset);
1387
+ currentOffset++;
1388
+ }
1389
+ if (flags & ARGS_ARE_XY_VALUES) {
1390
+ part.m.tx = arg1;
1391
+ part.m.ty = arg2;
1392
+ } else {
1393
+ part.p1 = arg1;
1394
+ part.p2 = arg2;
1395
+ }
1396
+ if (flags & WE_HAVE_A_SCALE) {
1397
+ part.m.a = part.m.d = bin.readF2dot14(data, currentOffset);
1398
+ currentOffset += 2;
1399
+ } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
1400
+ part.m.a = bin.readF2dot14(data, currentOffset);
1401
+ currentOffset += 2;
1402
+ part.m.d = bin.readF2dot14(data, currentOffset);
1403
+ currentOffset += 2;
1404
+ } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
1405
+ part.m.a = bin.readF2dot14(data, currentOffset);
1406
+ currentOffset += 2;
1407
+ part.m.b = bin.readF2dot14(data, currentOffset);
1408
+ currentOffset += 2;
1409
+ part.m.c = bin.readF2dot14(data, currentOffset);
1410
+ currentOffset += 2;
1411
+ part.m.d = bin.readF2dot14(data, currentOffset);
1412
+ currentOffset += 2;
1413
+ }
1414
+ } while (flags & MORE_COMPONENTS);
1415
+ if (flags & WE_HAVE_INSTRUCTIONS) {
1416
+ const numInstr = bin.readUshort(data, currentOffset);
1417
+ currentOffset += 2;
1418
+ gl.instr = [];
1419
+ for (let i = 0; i < numInstr; i++) {
1420
+ gl.instr.push(data[currentOffset]);
1421
+ currentOffset++;
1422
+ }
1423
+ }
1424
+ }
1425
+ return gl;
1426
+ }
1427
+ };
1428
+ T2.name = {
1429
+ parseTab: function(data, offset, length) {
1430
+ const bin = Typr2.B;
1431
+ const obj = {};
1432
+ const format = bin.readUshort(data, offset);
1433
+ offset += 2;
1434
+ const count = bin.readUshort(data, offset);
1435
+ offset += 2;
1436
+ const stringOffset = bin.readUshort(data, offset);
1437
+ offset += 2;
1438
+ const ooo = offset - 6 + stringOffset;
1439
+ const names = [
1440
+ "copyright",
1441
+ "fontFamily",
1442
+ "fontSubfamily",
1443
+ "ID",
1444
+ "fullName",
1445
+ "version",
1446
+ "postScriptName",
1447
+ "trademark",
1448
+ "manufacturer",
1449
+ "designer",
1450
+ "description",
1451
+ "urlVendor",
1452
+ "urlDesigner",
1453
+ "licence",
1454
+ "licenceURL",
1455
+ "---",
1456
+ "typoFamilyName",
1457
+ "typoSubfamilyName",
1458
+ "compatibleFull",
1459
+ "sampleText",
1460
+ "postScriptCID",
1461
+ "wwsFamilyName",
1462
+ "wwsSubfamilyName",
1463
+ "lightPalette",
1464
+ "darkPalette"
1465
+ ];
1466
+ const rU = bin.readUshort;
1467
+ for (let i = 0; i < count; i++) {
1468
+ const platformID = rU(data, offset);
1469
+ offset += 2;
1470
+ const encodingID = rU(data, offset);
1471
+ offset += 2;
1472
+ const languageID = rU(data, offset);
1473
+ offset += 2;
1474
+ const nameID = rU(data, offset);
1475
+ offset += 2;
1476
+ const slen = rU(data, offset);
1477
+ offset += 2;
1478
+ const noffset = rU(data, offset);
1479
+ offset += 2;
1480
+ const soff = ooo + noffset;
1481
+ let str;
1482
+ if (false) {
1483
+ } else if (platformID == 0)
1484
+ str = bin.readUnicode(data, soff, slen / 2);
1485
+ else if (platformID == 3 && encodingID == 0)
1486
+ str = bin.readUnicode(data, soff, slen / 2);
1487
+ else if (platformID == 1 && encodingID == 25)
1488
+ str = bin.readUnicode(data, soff, slen / 2);
1489
+ else if (encodingID == 0) str = bin.readASCII(data, soff, slen);
1490
+ else if (encodingID == 1) str = bin.readUnicode(data, soff, slen / 2);
1491
+ else if (encodingID == 3) str = bin.readUnicode(data, soff, slen / 2);
1492
+ else if (encodingID == 4) str = bin.readUnicode(data, soff, slen / 2);
1493
+ else if (encodingID == 5) str = bin.readUnicode(data, soff, slen / 2);
1494
+ else if (encodingID == 10)
1495
+ str = bin.readUnicode(data, soff, slen / 2);
1496
+ else if (platformID == 1) {
1497
+ str = bin.readASCII(data, soff, slen);
1498
+ console.log(
1499
+ "reading unknown MAC encoding " + encodingID + " as ASCII"
1500
+ );
1501
+ } else {
1502
+ console.log(
1503
+ "unknown encoding " + encodingID + ", platformID: " + platformID
1504
+ );
1505
+ str = bin.readASCII(data, soff, slen);
1506
+ }
1507
+ const tid = "p" + platformID + "," + languageID.toString(16);
1508
+ if (obj[tid] == null) obj[tid] = {};
1509
+ let name2 = names[nameID];
1510
+ if (name2 == null) name2 = "_" + nameID;
1511
+ obj[tid][name2] = str;
1512
+ obj[tid]["_lang"] = languageID;
1513
+ }
1514
+ const out = Typr2.T.name.selectOne(obj);
1515
+ const ff = "fontFamily";
1516
+ if (out[ff] == null) {
1517
+ for (const p in obj) if (obj[p][ff] != null) out[ff] = obj[p][ff];
1518
+ }
1519
+ return out;
1520
+ },
1521
+ selectOne: function(obj) {
1522
+ const psn = "postScriptName";
1523
+ for (const p in obj)
1524
+ if (obj[p][psn] != null && obj[p]["_lang"] == 1033) return obj[p];
1525
+ for (const p in obj)
1526
+ if (obj[p][psn] != null && obj[p]["_lang"] == 0) return obj[p];
1527
+ for (const p in obj)
1528
+ if (obj[p][psn] != null && obj[p]["_lang"] == 3084) return obj[p];
1529
+ for (const p in obj) if (obj[p][psn] != null) return obj[p];
1530
+ let out;
1531
+ for (const p in obj) {
1532
+ out = obj[p];
1533
+ break;
1534
+ }
1535
+ console.log("returning name table with languageID " + out._lang);
1536
+ if (out[psn] == null && out["ID"] != null) out[psn] = out["ID"];
1537
+ return out;
1538
+ }
1539
+ };
1540
+ T2.OS2 = {
1541
+ parseTab: function(data, offset, length) {
1542
+ const bin = Typr2.B;
1543
+ const ver = bin.readUshort(data, offset);
1544
+ offset += 2;
1545
+ const OS22 = Typr2.T.OS2;
1546
+ const obj = {};
1547
+ if (ver == 0) OS22.version0(data, offset, obj);
1548
+ else if (ver == 1) OS22.version1(data, offset, obj);
1549
+ else if (ver == 2 || ver == 3 || ver == 4)
1550
+ OS22.version2(data, offset, obj);
1551
+ else if (ver == 5) OS22.version5(data, offset, obj);
1552
+ else throw new Error("unknown OS/2 table version: " + ver);
1553
+ return obj;
1554
+ },
1555
+ version0: function(data, offset, obj) {
1556
+ const bin = Typr2.B;
1557
+ obj["xAvgCharWidth"] = bin.readShort(data, offset);
1558
+ offset += 2;
1559
+ obj["usWeightClass"] = bin.readUshort(data, offset);
1560
+ offset += 2;
1561
+ obj["usWidthClass"] = bin.readUshort(data, offset);
1562
+ offset += 2;
1563
+ obj["fsType"] = bin.readUshort(data, offset);
1564
+ offset += 2;
1565
+ obj["ySubscriptXSize"] = bin.readShort(data, offset);
1566
+ offset += 2;
1567
+ obj["ySubscriptYSize"] = bin.readShort(data, offset);
1568
+ offset += 2;
1569
+ obj["ySubscriptXOffset"] = bin.readShort(data, offset);
1570
+ offset += 2;
1571
+ obj["ySubscriptYOffset"] = bin.readShort(data, offset);
1572
+ offset += 2;
1573
+ obj["ySuperscriptXSize"] = bin.readShort(data, offset);
1574
+ offset += 2;
1575
+ obj["ySuperscriptYSize"] = bin.readShort(data, offset);
1576
+ offset += 2;
1577
+ obj["ySuperscriptXOffset"] = bin.readShort(data, offset);
1578
+ offset += 2;
1579
+ obj["ySuperscriptYOffset"] = bin.readShort(data, offset);
1580
+ offset += 2;
1581
+ obj["yStrikeoutSize"] = bin.readShort(data, offset);
1582
+ offset += 2;
1583
+ obj["yStrikeoutPosition"] = bin.readShort(data, offset);
1584
+ offset += 2;
1585
+ obj["sFamilyClass"] = bin.readShort(data, offset);
1586
+ offset += 2;
1587
+ obj["panose"] = bin.readBytes(data, offset, 10);
1588
+ offset += 10;
1589
+ obj["ulUnicodeRange1"] = bin.readUint(data, offset);
1590
+ offset += 4;
1591
+ obj["ulUnicodeRange2"] = bin.readUint(data, offset);
1592
+ offset += 4;
1593
+ obj["ulUnicodeRange3"] = bin.readUint(data, offset);
1594
+ offset += 4;
1595
+ obj["ulUnicodeRange4"] = bin.readUint(data, offset);
1596
+ offset += 4;
1597
+ obj["achVendID"] = bin.readASCII(data, offset, 4);
1598
+ offset += 4;
1599
+ obj["fsSelection"] = bin.readUshort(data, offset);
1600
+ offset += 2;
1601
+ obj["usFirstCharIndex"] = bin.readUshort(data, offset);
1602
+ offset += 2;
1603
+ obj["usLastCharIndex"] = bin.readUshort(data, offset);
1604
+ offset += 2;
1605
+ obj["sTypoAscender"] = bin.readShort(data, offset);
1606
+ offset += 2;
1607
+ obj["sTypoDescender"] = bin.readShort(data, offset);
1608
+ offset += 2;
1609
+ obj["sTypoLineGap"] = bin.readShort(data, offset);
1610
+ offset += 2;
1611
+ obj["usWinAscent"] = bin.readUshort(data, offset);
1612
+ offset += 2;
1613
+ obj["usWinDescent"] = bin.readUshort(data, offset);
1614
+ offset += 2;
1615
+ return offset;
1616
+ },
1617
+ version1: function(data, offset, obj) {
1618
+ const bin = Typr2.B;
1619
+ offset = Typr2.T.OS2.version0(data, offset, obj);
1620
+ obj["ulCodePageRange1"] = bin.readUint(data, offset);
1621
+ offset += 4;
1622
+ obj["ulCodePageRange2"] = bin.readUint(data, offset);
1623
+ offset += 4;
1624
+ return offset;
1625
+ },
1626
+ version2: function(data, offset, obj) {
1627
+ const bin = Typr2.B;
1628
+ const rU = bin.readUshort;
1629
+ offset = Typr2.T.OS2.version1(data, offset, obj);
1630
+ obj["sxHeight"] = bin.readShort(data, offset);
1631
+ offset += 2;
1632
+ obj["sCapHeight"] = bin.readShort(data, offset);
1633
+ offset += 2;
1634
+ obj["usDefault"] = rU(data, offset);
1635
+ offset += 2;
1636
+ obj["usBreak"] = rU(data, offset);
1637
+ offset += 2;
1638
+ obj["usMaxContext"] = rU(data, offset);
1639
+ offset += 2;
1640
+ return offset;
1641
+ },
1642
+ version5: function(data, offset, obj) {
1643
+ const rU = Typr2.B.readUshort;
1644
+ offset = Typr2.T.OS2.version2(data, offset, obj);
1645
+ obj["usLowerOpticalPointSize"] = rU(data, offset);
1646
+ offset += 2;
1647
+ obj["usUpperOpticalPointSize"] = rU(data, offset);
1648
+ offset += 2;
1649
+ return offset;
1650
+ }
1651
+ };
1652
+ T2.post = {
1653
+ parseTab: function(data, offset, length) {
1654
+ const bin = Typr2.B;
1655
+ const obj = {};
1656
+ obj.version = bin.readFixed(data, offset);
1657
+ offset += 4;
1658
+ obj.italicAngle = bin.readFixed(data, offset);
1659
+ offset += 4;
1660
+ obj.underlinePosition = bin.readShort(data, offset);
1661
+ offset += 2;
1662
+ obj.underlineThickness = bin.readShort(data, offset);
1663
+ offset += 2;
1664
+ return obj;
1665
+ }
1666
+ };
1667
+ T2.kern = {
1668
+ parseTab: function(data, offset, length, font) {
1669
+ const bin = Typr2.B;
1670
+ const kern2 = Typr2.T.kern;
1671
+ const version = bin.readUshort(data, offset);
1672
+ if (version == 1) return kern2.parseV1(data, offset, length, font);
1673
+ const nTables = bin.readUshort(data, offset + 2);
1674
+ offset += 4;
1675
+ const map = { glyph1: [], rval: [] };
1676
+ for (let i = 0; i < nTables; i++) {
1677
+ offset += 2;
1678
+ const length2 = bin.readUshort(data, offset);
1679
+ offset += 2;
1680
+ const coverage = bin.readUshort(data, offset);
1681
+ offset += 2;
1682
+ let format = coverage >>> 8;
1683
+ format &= 15;
1684
+ if (format == 0) offset = kern2.readFormat0(data, offset, map);
1685
+ }
1686
+ return map;
1687
+ },
1688
+ parseV1: function(data, offset, length, font) {
1689
+ const bin = Typr2.B;
1690
+ const kern2 = Typr2.T.kern;
1691
+ const version = bin.readFixed(data, offset);
1692
+ const nTables = bin.readUint(data, offset + 4);
1693
+ offset += 8;
1694
+ const map = { glyph1: [], rval: [] };
1695
+ for (let i = 0; i < nTables; i++) {
1696
+ const length2 = bin.readUint(data, offset);
1697
+ offset += 4;
1698
+ const coverage = bin.readUshort(data, offset);
1699
+ offset += 2;
1700
+ const tupleIndex = bin.readUshort(data, offset);
1701
+ offset += 2;
1702
+ const format = coverage & 255;
1703
+ if (format == 0) offset = kern2.readFormat0(data, offset, map);
1704
+ }
1705
+ return map;
1706
+ },
1707
+ readFormat0: function(data, offset, map) {
1708
+ const bin = Typr2.B;
1709
+ const rUs = bin.readUshort;
1710
+ let pleft = -1;
1711
+ const nPairs = rUs(data, offset);
1712
+ const searchRange = rUs(data, offset + 2);
1713
+ const entrySelector = rUs(data, offset + 4);
1714
+ const rangeShift = rUs(data, offset + 6);
1715
+ offset += 8;
1716
+ for (let j = 0; j < nPairs; j++) {
1717
+ const left = rUs(data, offset);
1718
+ offset += 2;
1719
+ const right = rUs(data, offset);
1720
+ offset += 2;
1721
+ const value = bin.readShort(data, offset);
1722
+ offset += 2;
1723
+ if (left != pleft) {
1724
+ map.glyph1.push(left);
1725
+ map.rval.push({ glyph2: [], vals: [] });
1726
+ }
1727
+ const rval = map.rval[map.rval.length - 1];
1728
+ rval.glyph2.push(right);
1729
+ rval.vals.push(value);
1730
+ pleft = left;
1731
+ }
1732
+ return offset;
1733
+ }
1734
+ };
1735
+ T2.GSUB = {
1736
+ parseTab: function(data, offset, length, obj) {
1737
+ const bin = Typr2.B;
1738
+ const rU = bin.readUshort;
1739
+ let off = offset;
1740
+ const maj = rU(data, off);
1741
+ off += 2;
1742
+ const min = rU(data, off);
1743
+ off += 2;
1744
+ const slO = rU(data, off);
1745
+ off += 2;
1746
+ const flO = rU(data, off);
1747
+ off += 2;
1748
+ const llO = rU(data, off);
1749
+ off += 2;
1750
+ const name2 = obj.name || {};
1751
+ const flBase = offset + flO;
1752
+ let foff = flBase;
1753
+ const fcnt = rU(data, foff);
1754
+ foff += 2;
1755
+ const features = {};
1756
+ for (let i = 0; i < fcnt; i++) {
1757
+ const tag = bin.readASCII(data, foff, 4);
1758
+ foff += 4;
1759
+ const fo = rU(data, foff);
1760
+ foff += 2;
1761
+ const rOff = flBase + fo;
1762
+ const pOff = rU(data, rOff);
1763
+ const lcnt = rU(data, rOff + 2);
1764
+ const lookups = [];
1765
+ let lo = rOff + 4;
1766
+ for (let j = 0; j < lcnt; j++) {
1767
+ lookups.push(rU(data, lo));
1768
+ lo += 2;
1769
+ }
1770
+ const feat = { tag, lookups };
1771
+ if (pOff !== 0) {
1772
+ const po = rOff + pOff;
1773
+ if (/^ss\d\d$/i.test(tag)) {
1774
+ const ui = rU(data, po + 2);
1775
+ feat.uiName = name2["_" + ui];
1776
+ } else if (/^cv\d\d$/i.test(tag)) {
1777
+ const ui = rU(data, po + 2);
1778
+ const ti = rU(data, po + 4);
1779
+ const si = rU(data, po + 6);
1780
+ const pcnt = rU(data, po + 8);
1781
+ const first = rU(data, po + 10);
1782
+ const labels = [];
1783
+ for (let k = 0; k < pcnt; k++) {
1784
+ const str = name2["_" + (first + k)];
1785
+ if (str) labels.push(str);
1786
+ }
1787
+ feat.uiName = name2["_" + ui];
1788
+ feat.tooltip = name2["_" + ti];
1789
+ feat.sampleText = name2["_" + si];
1790
+ if (labels.length) feat.paramLabels = labels;
1791
+ }
1792
+ }
1793
+ features[tag] = feat;
1794
+ }
1795
+ return { features };
1796
+ }
1797
+ };
1798
+ T2.CBLC = {
1799
+ parseTab: function(data, offset, length) {
1800
+ const bin = Typr2.B;
1801
+ const ooff = offset;
1802
+ const maj = bin.readUshort(data, offset);
1803
+ offset += 2;
1804
+ const min = bin.readUshort(data, offset);
1805
+ offset += 2;
1806
+ const numSizes = bin.readUint(data, offset);
1807
+ offset += 4;
1808
+ const out = [];
1809
+ for (let i = 0; i < numSizes; i++) {
1810
+ const off = bin.readUint(data, offset);
1811
+ offset += 4;
1812
+ const siz = bin.readUint(data, offset);
1813
+ offset += 4;
1814
+ const num = bin.readUint(data, offset);
1815
+ offset += 4;
1816
+ offset += 4;
1817
+ offset += 2 * 12;
1818
+ const sGlyph = bin.readUshort(data, offset);
1819
+ offset += 2;
1820
+ const eGlyph = bin.readUshort(data, offset);
1821
+ offset += 2;
1822
+ offset += 4;
1823
+ let coff = ooff + off;
1824
+ for (let j = 0; j < 3; j++) {
1825
+ const fgI = bin.readUshort(data, coff);
1826
+ coff += 2;
1827
+ const lgI = bin.readUshort(data, coff);
1828
+ coff += 2;
1829
+ const nxt = bin.readUint(data, coff);
1830
+ coff += 4;
1831
+ const gcnt = lgI - fgI + 1;
1832
+ let ioff = ooff + off + nxt;
1833
+ const inF = bin.readUshort(data, ioff);
1834
+ ioff += 2;
1835
+ if (inF != 1) throw new Error(`Invalid format: ${inF}`);
1836
+ const imF = bin.readUshort(data, ioff);
1837
+ ioff += 2;
1838
+ const imgo = bin.readUint(data, ioff);
1839
+ ioff += 4;
1840
+ const oarr = [];
1841
+ for (let gi = 0; gi < gcnt; gi++) {
1842
+ const sbitO = bin.readUint(data, ioff + gi * 4);
1843
+ oarr.push(imgo + sbitO);
1844
+ }
1845
+ out.push([fgI, lgI, imF, oarr]);
1846
+ }
1847
+ }
1848
+ return out;
1849
+ }
1850
+ };
1851
+ T2.CBDT = {
1852
+ parseTab: function(data, offset, length) {
1853
+ return new Uint8Array(data.buffer, data.byteOffset + offset, length);
1854
+ }
1855
+ };
1856
+ T2.SVG = {
1857
+ parseTab: function(data, offset, length) {
1858
+ const bin = Typr2.B;
1859
+ const obj = { entries: [], svgs: [] };
1860
+ const offset0 = offset;
1861
+ const tableVersion = bin.readUshort(data, offset);
1862
+ offset += 2;
1863
+ const svgDocIndexOffset = bin.readUint(data, offset);
1864
+ offset += 4;
1865
+ const reserved = bin.readUint(data, offset);
1866
+ offset += 4;
1867
+ offset = svgDocIndexOffset + offset0;
1868
+ const numEntries = bin.readUshort(data, offset);
1869
+ offset += 2;
1870
+ for (let i = 0; i < numEntries; i++) {
1871
+ const startGlyphID = bin.readUshort(data, offset);
1872
+ offset += 2;
1873
+ const endGlyphID = bin.readUshort(data, offset);
1874
+ offset += 2;
1875
+ const svgDocOffset = bin.readUint(data, offset);
1876
+ offset += 4;
1877
+ const svgDocLength = bin.readUint(data, offset);
1878
+ offset += 4;
1879
+ const sbuf = new Uint8Array(
1880
+ data.buffer,
1881
+ offset0 + svgDocOffset + svgDocIndexOffset,
1882
+ svgDocLength
1883
+ );
1884
+ const svg = bin.readUTF8(sbuf, 0, sbuf.length);
1885
+ for (let f = startGlyphID; f <= endGlyphID; f++) {
1886
+ obj.entries[f] = obj.svgs.length;
1887
+ }
1888
+ obj.svgs.push(svg);
1889
+ }
1890
+ return obj;
1891
+ }
1892
+ };
1893
+ T2.colr = {
1894
+ parseTab: function(data, offset, length) {
1895
+ const bin = Typr2.B;
1896
+ const ooff = offset;
1897
+ offset += 2;
1898
+ const num = bin.readUshort(data, offset);
1899
+ offset += 2;
1900
+ const boff = bin.readUint(data, offset);
1901
+ offset += 4;
1902
+ const loff = bin.readUint(data, offset);
1903
+ offset += 4;
1904
+ const lnum = bin.readUshort(data, offset);
1905
+ offset += 2;
1906
+ const base = {};
1907
+ let coff = ooff + boff;
1908
+ for (let i = 0; i < num; i++) {
1909
+ base["g" + bin.readUshort(data, coff)] = [
1910
+ bin.readUshort(data, coff + 2),
1911
+ bin.readUshort(data, coff + 4)
1912
+ ];
1913
+ coff += 6;
1914
+ }
1915
+ const lays = [];
1916
+ coff = ooff + loff;
1917
+ for (let i = 0; i < lnum; i++) {
1918
+ lays.push(bin.readUshort(data, coff), bin.readUshort(data, coff + 2));
1919
+ coff += 4;
1920
+ }
1921
+ return [base, lays];
1922
+ }
1923
+ };
1924
+ T2.cpal = {
1925
+ parseTab: function(data, offset, length) {
1926
+ const bin = Typr2.B;
1927
+ const ooff = offset;
1928
+ const vsn = bin.readUshort(data, offset);
1929
+ offset += 2;
1930
+ if (vsn == 0) {
1931
+ const ets = bin.readUshort(data, offset);
1932
+ offset += 2;
1933
+ const pts = bin.readUshort(data, offset);
1934
+ offset += 2;
1935
+ const tot = bin.readUshort(data, offset);
1936
+ offset += 2;
1937
+ const fst = bin.readUint(data, offset);
1938
+ offset += 4;
1939
+ return new Uint8Array(data.buffer, ooff + fst, tot * 4);
1940
+ } else throw new Error(`Unknown color palette version: ${vsn}`);
1941
+ }
1942
+ };
1943
+ T2.sbix = {
1944
+ parseTab: function(data, offset, length, obj) {
1945
+ const numGlyphs = obj["maxp"]["numGlyphs"];
1946
+ const ooff = offset;
1947
+ const bin = Typr2.B;
1948
+ const numStrikes = bin.readUint(data, offset + 4);
1949
+ const out = [];
1950
+ for (let si = numStrikes - 1; si < numStrikes; si++) {
1951
+ const off = ooff + bin.readUint(data, offset + 8 + si * 4);
1952
+ for (let gi = 0; gi < numGlyphs; gi++) {
1953
+ const aoff = bin.readUint(data, off + 4 + gi * 4);
1954
+ const noff = bin.readUint(data, off + 4 + gi * 4 + 4);
1955
+ if (aoff == noff) {
1956
+ out[gi] = null;
1957
+ continue;
1958
+ }
1959
+ const go = off + aoff;
1960
+ const tag = bin.readASCII(data, go + 4, 4);
1961
+ if (tag != "png ") throw new Error(`Invalid tag: ${tag}`);
1962
+ out[gi] = new Uint8Array(
1963
+ data.buffer,
1964
+ data.byteOffset + go + 8,
1965
+ noff - aoff - 8
1966
+ );
1967
+ }
1968
+ }
1969
+ return out;
1970
+ }
1971
+ };
1972
+ T2.fvar = {
1973
+ parseTab: function(data, offset, length, obj) {
1974
+ const name2 = obj["name"];
1975
+ let off = offset;
1976
+ const bin = Typr2.B;
1977
+ const axes = [];
1978
+ const inst = [];
1979
+ off += 8;
1980
+ const acnt = bin.readUshort(data, off);
1981
+ off += 2;
1982
+ off += 2;
1983
+ const icnt = bin.readUshort(data, off);
1984
+ off += 2;
1985
+ const isiz = bin.readUshort(data, off);
1986
+ off += 2;
1987
+ for (let i = 0; i < acnt; i++) {
1988
+ const tag = bin.readASCII(data, off, 4);
1989
+ const min = bin.readFixed(data, off + 4);
1990
+ const def = bin.readFixed(data, off + 8);
1991
+ const max = bin.readFixed(data, off + 12);
1992
+ const flg = bin.readUshort(data, off + 16);
1993
+ const nid = bin.readUshort(data, off + 18);
1994
+ axes.push([tag, min, def, max, flg, name2["_" + nid]]);
1995
+ off += 20;
1996
+ }
1997
+ for (let i = 0; i < icnt; i++) {
1998
+ const snid = bin.readUshort(data, off);
1999
+ let pnid = null;
2000
+ const flg = bin.readUshort(data, off + 2);
2001
+ const crd = [];
2002
+ for (let j = 0; j < acnt; j++)
2003
+ crd.push(bin.readFixed(data, off + 4 + j * 4));
2004
+ off += 4 + acnt * 4;
2005
+ if ((isiz & 3) == 2) {
2006
+ pnid = bin.readUshort(data, off);
2007
+ off += 2;
2008
+ }
2009
+ inst.push([name2["_" + snid], flg, crd, pnid]);
2010
+ }
2011
+ return [axes, inst];
2012
+ }
2013
+ };
2014
+ T2.gvar = {
2015
+ parseTab: function(data, offset, length, obj) {
2016
+ const EMBEDDED_PEAK_TUPLE = 32768;
2017
+ const INTERMEDIATE_REGION = 16384;
2018
+ const PRIVATE_POINT_NUMBERS = 8192;
2019
+ const DELTAS_ARE_ZERO = 128;
2020
+ const DELTAS_ARE_WORDS = 64;
2021
+ const POINTS_ARE_WORDS = 128;
2022
+ const SHARED_POINT_NUMBERS = 32768;
2023
+ const bin = Typr2.B;
2024
+ function readTuple(data2, o, acnt2) {
2025
+ const tup = [];
2026
+ for (let j = 0; j < acnt2; j++)
2027
+ tup.push(bin.readF2dot14(data2, o + j * 2));
2028
+ return tup;
2029
+ }
2030
+ function readTupleVarHeader(data2, off2, vcnt, acnt2, eoff) {
2031
+ const out = [];
2032
+ for (let j = 0; j < vcnt; j++) {
2033
+ const dsiz = bin.readUshort(data2, off2);
2034
+ off2 += 2;
2035
+ let tind = bin.readUshort(data2, off2);
2036
+ const flag = tind & 61440;
2037
+ tind = tind & 4095;
2038
+ off2 += 2;
2039
+ let peak = null;
2040
+ let start = null;
2041
+ let end = null;
2042
+ if (flag & EMBEDDED_PEAK_TUPLE) {
2043
+ peak = readTuple(data2, off2, acnt2);
2044
+ off2 += acnt2 * 2;
2045
+ }
2046
+ if (flag & INTERMEDIATE_REGION) {
2047
+ start = readTuple(data2, off2, acnt2);
2048
+ off2 += acnt2 * 2;
2049
+ }
2050
+ if (flag & INTERMEDIATE_REGION) {
2051
+ end = readTuple(data2, off2, acnt2);
2052
+ off2 += acnt2 * 2;
2053
+ }
2054
+ out.push([dsiz, tind, flag, start, peak, end]);
2055
+ }
2056
+ return out;
2057
+ }
2058
+ function readPointNumbers(data2, off2, gid) {
2059
+ let cnt = data2[off2];
2060
+ off2++;
2061
+ if (cnt == 0) return [[], off2];
2062
+ if (127 < cnt) {
2063
+ cnt = (cnt & 127) << 8 | data2[off2++];
2064
+ }
2065
+ const pts = [];
2066
+ let last = 0;
2067
+ while (pts.length < cnt) {
2068
+ const v = data2[off2++];
2069
+ const wds = (v & POINTS_ARE_WORDS) != 0;
2070
+ const vv = (v & 127) + 1;
2071
+ for (let i = 0; i < vv; i++) {
2072
+ let dif = 0;
2073
+ if (wds) {
2074
+ dif = bin.readUshort(data2, off2);
2075
+ off2 += 2;
2076
+ } else {
2077
+ dif = data2[off2];
2078
+ off2++;
2079
+ }
2080
+ last += dif;
2081
+ pts.push(last);
2082
+ }
2083
+ }
2084
+ return [pts, off2];
2085
+ }
2086
+ let off = offset + 4;
2087
+ const acnt = bin.readUshort(data, off);
2088
+ off += 2;
2089
+ const tcnt = bin.readUshort(data, off);
2090
+ off += 2;
2091
+ const toff = bin.readUint(data, off);
2092
+ off += 4;
2093
+ const gcnt = bin.readUshort(data, off);
2094
+ off += 2;
2095
+ const flgs = bin.readUshort(data, off);
2096
+ off += 2;
2097
+ const goff = bin.readUint(data, off);
2098
+ off += 4;
2099
+ const offs = [];
2100
+ for (let i = 0; i < gcnt + 1; i++)
2101
+ offs.push(bin.readUint(data, off + i * 4));
2102
+ const tups = [];
2103
+ const mins = [];
2104
+ const maxs = [];
2105
+ off = offset + toff;
2106
+ for (let i = 0; i < tcnt; i++) {
2107
+ const peak = readTuple(data, off + i * acnt * 2, acnt);
2108
+ const imin = [];
2109
+ const imax = [];
2110
+ tups.push(peak);
2111
+ mins.push(imin);
2112
+ maxs.push(imax);
2113
+ for (let k = 0; k < acnt; k++) {
2114
+ imin[k] = Math.min(peak[k], 0);
2115
+ imax[k] = Math.max(peak[k], 0);
2116
+ }
2117
+ }
2118
+ const i8 = new Int8Array(data.buffer);
2119
+ const tabs = [];
2120
+ for (let i = 0; i < gcnt; i++) {
2121
+ off = offset + goff + offs[i];
2122
+ let vcnt = bin.readUshort(data, off);
2123
+ off += 2;
2124
+ const snum = vcnt & SHARED_POINT_NUMBERS;
2125
+ vcnt &= 4095;
2126
+ const soff = bin.readUshort(data, off);
2127
+ off += 2;
2128
+ const hdr = readTupleVarHeader(
2129
+ data,
2130
+ off,
2131
+ vcnt,
2132
+ acnt,
2133
+ offset + goff + offs[i + 1]
2134
+ );
2135
+ const tab = [];
2136
+ tabs.push(tab);
2137
+ off = offset + goff + offs[i] + soff;
2138
+ let sind = null;
2139
+ if (snum) {
2140
+ const oo = readPointNumbers(data, off, i);
2141
+ sind = oo[0];
2142
+ off = oo[1];
2143
+ }
2144
+ for (let j = 0; j < vcnt; j++) {
2145
+ const vr = hdr[j];
2146
+ const end = off + vr[0];
2147
+ let ind = sind;
2148
+ if (vr[2] & PRIVATE_POINT_NUMBERS) {
2149
+ const oo = readPointNumbers(data, off, i);
2150
+ ind = oo[0];
2151
+ off = oo[1];
2152
+ }
2153
+ const ds = [];
2154
+ while (off < end) {
2155
+ const cb = data[off++];
2156
+ const cnt = (cb & 63) + 1;
2157
+ if (cb & DELTAS_ARE_ZERO) {
2158
+ for (let k = 0; k < cnt; k++) ds.push(0);
2159
+ } else if (cb & DELTAS_ARE_WORDS) {
2160
+ for (let k = 0; k < cnt; k++)
2161
+ ds.push(bin.readShort(data, off + k * 2));
2162
+ off += cnt * 2;
2163
+ } else {
2164
+ for (let k = 0; k < cnt; k++) ds.push(i8[off + k]);
2165
+ off += cnt;
2166
+ }
2167
+ }
2168
+ const ti = vr[1];
2169
+ const outInd = ind && ind.length * 2 == ds.length ? ind : null;
2170
+ tab.push([
2171
+ [
2172
+ vr[3] ? vr[3] : mins[ti],
2173
+ vr[4] ? vr[4] : tups[ti],
2174
+ vr[5] ? vr[5] : maxs[ti]
2175
+ ],
2176
+ ds,
2177
+ outInd
2178
+ ]);
2179
+ }
2180
+ }
2181
+ return tabs;
2182
+ }
2183
+ };
2184
+ T2.avar = {
2185
+ parseTab: function(data, offset, length, obj) {
2186
+ let off = offset;
2187
+ const bin = Typr2.B;
2188
+ const out = [];
2189
+ off += 6;
2190
+ const acnt = bin.readUshort(data, off);
2191
+ off += 2;
2192
+ for (let ai = 0; ai < acnt; ai++) {
2193
+ const cnt = bin.readUshort(data, off);
2194
+ off += 2;
2195
+ const poly = [];
2196
+ out.push(poly);
2197
+ for (let i = 0; i < cnt; i++) {
2198
+ const x = bin.readF2dot14(data, off);
2199
+ const y = bin.readF2dot14(data, off + 2);
2200
+ off += 4;
2201
+ poly.push(x, y);
2202
+ }
2203
+ }
2204
+ return out;
2205
+ }
2206
+ };
2207
+ T2.STAT = {
2208
+ parseTab: function(data, offset, length, font) {
2209
+ const bin = Typr2.B;
2210
+ let off = offset;
2211
+ const majorVersion = bin.readUshort(data, off);
2212
+ off += 2;
2213
+ const minorVersion = bin.readUshort(data, off);
2214
+ off += 2;
2215
+ const designAxisSize = bin.readUshort(data, off);
2216
+ off += 2;
2217
+ const designAxisCount = bin.readUshort(data, off);
2218
+ off += 2;
2219
+ const designAxesOffset = bin.readUint(data, off);
2220
+ off += 4;
2221
+ const axisValueCount = bin.readUshort(data, off);
2222
+ off += 2;
2223
+ const axisValueOffsetsOffset = bin.readUint(data, off);
2224
+ off += 4;
2225
+ let elidedFallbackNameID;
2226
+ if (majorVersion > 1 || majorVersion === 1 && minorVersion >= 1) {
2227
+ elidedFallbackNameID = bin.readUshort(data, off);
2228
+ off += 2;
2229
+ }
2230
+ const name2 = font.name || {};
2231
+ const designAxes = [];
2232
+ if (designAxisCount > 0) {
2233
+ let aoff = offset + designAxesOffset;
2234
+ for (let i = 0; i < designAxisCount; i++) {
2235
+ const tag = bin.readASCII(data, aoff, 4);
2236
+ const axisNameID = bin.readUshort(data, aoff + 4);
2237
+ const ordering = bin.readUshort(data, aoff + 6);
2238
+ designAxes.push({ tag, name: name2["_" + axisNameID], ordering });
2239
+ aoff += designAxisSize;
2240
+ }
2241
+ }
2242
+ const valueOffsets = [];
2243
+ if (axisValueCount > 0) {
2244
+ const arrBase = offset + axisValueOffsetsOffset;
2245
+ let voff = arrBase;
2246
+ for (let i = 0; i < axisValueCount; i++) {
2247
+ const relOff = bin.readUshort(data, voff);
2248
+ valueOffsets.push(arrBase + relOff);
2249
+ voff += 2;
2250
+ }
2251
+ }
2252
+ const axisValues = [];
2253
+ for (const rel of valueOffsets) {
2254
+ let voff = rel;
2255
+ const format = bin.readUshort(data, voff);
2256
+ voff += 2;
2257
+ if (format === 1) {
2258
+ const axisIndex = bin.readUshort(data, voff);
2259
+ voff += 2;
2260
+ const flags = bin.readUshort(data, voff);
2261
+ voff += 2;
2262
+ const valueNameID = bin.readUshort(data, voff);
2263
+ voff += 2;
2264
+ const value = bin.readFixed(data, voff);
2265
+ axisValues.push({
2266
+ format: 1,
2267
+ axisIndex,
2268
+ flags,
2269
+ name: name2["_" + valueNameID],
2270
+ value
2271
+ });
2272
+ } else if (format === 2) {
2273
+ const axisIndex = bin.readUshort(data, voff);
2274
+ voff += 2;
2275
+ const flags = bin.readUshort(data, voff);
2276
+ voff += 2;
2277
+ const valueNameID = bin.readUshort(data, voff);
2278
+ voff += 2;
2279
+ const nominalValue = bin.readFixed(data, voff);
2280
+ voff += 4;
2281
+ const rangeMinValue = bin.readFixed(data, voff);
2282
+ voff += 4;
2283
+ const rangeMaxValue = bin.readFixed(data, voff);
2284
+ axisValues.push({
2285
+ format: 2,
2286
+ axisIndex,
2287
+ flags,
2288
+ name: name2["_" + valueNameID],
2289
+ nominalValue,
2290
+ rangeMinValue,
2291
+ rangeMaxValue
2292
+ });
2293
+ } else if (format === 3) {
2294
+ const axisIndex = bin.readUshort(data, voff);
2295
+ voff += 2;
2296
+ const flags = bin.readUshort(data, voff);
2297
+ voff += 2;
2298
+ const valueNameID = bin.readUshort(data, voff);
2299
+ voff += 2;
2300
+ const value = bin.readFixed(data, voff);
2301
+ voff += 4;
2302
+ const linkedValue = bin.readFixed(data, voff);
2303
+ axisValues.push({
2304
+ format: 3,
2305
+ axisIndex,
2306
+ flags,
2307
+ name: name2["_" + valueNameID],
2308
+ value,
2309
+ linkedValue
2310
+ });
2311
+ } else if (format === 4) {
2312
+ const axisCount = bin.readUshort(data, voff);
2313
+ voff += 2;
2314
+ const flags = bin.readUshort(data, voff);
2315
+ voff += 2;
2316
+ const valueNameID = bin.readUshort(data, voff);
2317
+ voff += 2;
2318
+ const axisValuesArr = [];
2319
+ for (let i = 0; i < axisCount; i++) {
2320
+ const axisIndex = bin.readUshort(data, voff);
2321
+ const value = bin.readFixed(data, voff + 2);
2322
+ voff += 6;
2323
+ axisValuesArr.push({ axisIndex, value });
2324
+ }
2325
+ axisValues.push({
2326
+ format: 4,
2327
+ flags,
2328
+ name: name2["_" + valueNameID],
2329
+ axisValues: axisValuesArr
2330
+ });
2331
+ }
2332
+ }
2333
+ return {
2334
+ majorVersion,
2335
+ minorVersion,
2336
+ designAxes,
2337
+ axisValues,
2338
+ elidedFallbackNameID
2339
+ };
2340
+ }
2341
+ };
2342
+ T2.HVAR = {
2343
+ parseTab: function(data, offset, length, obj) {
2344
+ let off = offset;
2345
+ const oo = offset;
2346
+ const bin = Typr2.B;
2347
+ const out = [];
2348
+ off += 4;
2349
+ const varO = bin.readUint(data, off);
2350
+ off += 4;
2351
+ const advO = bin.readUint(data, off);
2352
+ off += 4;
2353
+ const lsbO = bin.readUint(data, off);
2354
+ off += 4;
2355
+ const rsbO = bin.readUint(data, off);
2356
+ off += 4;
2357
+ if (lsbO != 0 || rsbO != 0) throw new Error(`Invalid offset: ${lsbO}`);
2358
+ off = oo + varO;
2359
+ const ioff = off;
2360
+ const fmt = bin.readUshort(data, off);
2361
+ off += 2;
2362
+ if (fmt != 1) throw new Error("Invalid format");
2363
+ const vregO = bin.readUint(data, off);
2364
+ off += 4;
2365
+ const vcnt = bin.readUshort(data, off);
2366
+ off += 2;
2367
+ const offs = [];
2368
+ for (let i = 0; i < vcnt; i++)
2369
+ offs.push(bin.readUint(data, off + i * 4));
2370
+ off += vcnt * 4;
2371
+ off = ioff + vregO;
2372
+ const acnt = bin.readUshort(data, off);
2373
+ off += 2;
2374
+ const rcnt = bin.readUshort(data, off);
2375
+ off += 2;
2376
+ const regs = [];
2377
+ for (let i = 0; i < rcnt; i++) {
2378
+ const crd = [[], [], []];
2379
+ regs.push(crd);
2380
+ for (let j = 0; j < acnt; j++) {
2381
+ crd[0].push(bin.readF2dot14(data, off + 0));
2382
+ crd[1].push(bin.readF2dot14(data, off + 2));
2383
+ crd[2].push(bin.readF2dot14(data, off + 4));
2384
+ off += 6;
2385
+ }
2386
+ }
2387
+ const i8 = new Int8Array(data.buffer);
2388
+ const varStore = [];
2389
+ for (let i = 0; i < offs.length; i++) {
2390
+ off = oo + varO + offs[i];
2391
+ const vdata = [];
2392
+ varStore.push(vdata);
2393
+ const icnt = bin.readUshort(data, off);
2394
+ off += 2;
2395
+ const dcnt = bin.readUshort(data, off);
2396
+ off += 2;
2397
+ if (dcnt & 32768) throw new Error("Invalid delta count");
2398
+ const rcnt2 = bin.readUshort(data, off);
2399
+ off += 2;
2400
+ const ixs = [];
2401
+ for (let j = 0; j < rcnt2; j++)
2402
+ ixs.push(bin.readUshort(data, off + j * 2));
2403
+ off += rcnt2 * 2;
2404
+ for (let k = 0; k < icnt; k++) {
2405
+ const deltaData = [];
2406
+ for (let ri = 0; ri < rcnt2; ri++) {
2407
+ deltaData.push(ri < dcnt ? bin.readShort(data, off) : i8[off]);
2408
+ off += ri < dcnt ? 2 : 1;
2409
+ }
2410
+ const dd = new Array(regs.length);
2411
+ dd.fill(0);
2412
+ vdata.push(dd);
2413
+ for (let j = 0; j < ixs.length; j++) {
2414
+ if (ixs[j] < dd.length && j < deltaData.length) {
2415
+ dd[ixs[j]] = deltaData[j];
2416
+ }
2417
+ }
2418
+ }
2419
+ }
2420
+ off = oo + advO;
2421
+ const fmt2 = data[off++];
2422
+ if (fmt2 != 0) throw new Error("Invalid format");
2423
+ const entryFormat = data[off++];
2424
+ const mapCount = bin.readUshort(data, off);
2425
+ off += 2;
2426
+ const INNER_INDEX_BIT_COUNT_MASK = 15;
2427
+ const MAP_ENTRY_SIZE_MASK = 48;
2428
+ const entrySize = ((entryFormat & MAP_ENTRY_SIZE_MASK) >> 4) + 1;
2429
+ const dfs = [];
2430
+ for (let i = 0; i < mapCount; i++) {
2431
+ let entry = 0;
2432
+ if (entrySize == 1) entry = data[off++];
2433
+ else {
2434
+ entry = bin.readUshort(data, off);
2435
+ off += 2;
2436
+ }
2437
+ const outerIndex = entry >> (entryFormat & INNER_INDEX_BIT_COUNT_MASK) + 1;
2438
+ const innerIndex = entry & (1 << (entryFormat & INNER_INDEX_BIT_COUNT_MASK) + 1) - 1;
2439
+ if (outerIndex < varStore.length && varStore[outerIndex] && innerIndex < varStore[outerIndex].length) {
2440
+ dfs.push(varStore[outerIndex][innerIndex]);
2441
+ } else {
2442
+ const defaultDelta = new Array(regs.length);
2443
+ defaultDelta.fill(0);
2444
+ dfs.push(defaultDelta);
2445
+ }
2446
+ }
2447
+ return [regs, dfs];
2448
+ }
2449
+ };
2450
+ })(T = Typr2.T || (Typr2.T = {}));
2451
+ })(Typr || (Typr = {}));
2452
+ var typr_default = Typr;
2453
+
2454
+ // cli.ts
22
2455
  var FORMAT_SET = /* @__PURE__ */ new Set(["png", "jpeg", "webp", "pdf", "svg"]);
23
2456
  var DOCUMENT_JSON = "document.json";
24
2457
  var IMAGES_SUBDIR = "images";
2458
+ var FONTS_SUBDIR = "fonts";
2459
+ var FONT_EXTENSIONS = /* @__PURE__ */ new Set([".ttf", ".otf"]);
2460
+ var LARGE_FILE_THRESHOLD = 2 * 1024 * 1024 * 1024;
25
2461
  function formatFromOutFile(outPath) {
26
2462
  const ext = path.extname(outPath).replace(/^\./, "").toLowerCase();
27
2463
  if (ext === "jpg") return "jpeg";
@@ -38,7 +2474,7 @@ var EXT_BY_FORMAT = {
38
2474
  function sanitizeForFilename(s) {
39
2475
  return String(s).replace(/[:/\\]/g, "_").replace(/\s+/g, "_") || "_";
40
2476
  }
41
- function resolveInput(inputPath, explicitImagesDir) {
2477
+ function resolveInput(inputPath, explicitImagesDir, explicitFontsDir) {
42
2478
  const resolved = path.resolve(inputPath);
43
2479
  const stat = statSync(resolved);
44
2480
  if (stat.isDirectory()) {
@@ -50,15 +2486,19 @@ function resolveInput(inputPath, explicitImagesDir) {
50
2486
  }
51
2487
  const imagesDir = path.join(resolved, IMAGES_SUBDIR);
52
2488
  const useImagesDir = existsSync(imagesDir) && statSync(imagesDir).isDirectory() ? imagesDir : void 0;
2489
+ const fontsDir = path.join(resolved, FONTS_SUBDIR);
2490
+ const useFontsDir = existsSync(fontsDir) && statSync(fontsDir).isDirectory() ? fontsDir : void 0;
53
2491
  return {
54
2492
  documentPath,
55
2493
  imagesDir: explicitImagesDir ? path.resolve(explicitImagesDir) : useImagesDir,
2494
+ fontsDir: explicitFontsDir ? path.resolve(explicitFontsDir) : useFontsDir,
56
2495
  isRestJson: true
57
2496
  };
58
2497
  }
59
2498
  return {
60
2499
  documentPath: resolved,
61
2500
  imagesDir: explicitImagesDir ? path.resolve(explicitImagesDir) : void 0,
2501
+ fontsDir: explicitFontsDir ? path.resolve(explicitFontsDir) : void 0,
62
2502
  isRestJson: resolved.toLowerCase().endsWith(".json")
63
2503
  };
64
2504
  }
@@ -74,6 +2514,43 @@ function readImagesFromDir(dirPath) {
74
2514
  }
75
2515
  return out;
76
2516
  }
2517
+ function* walkFontFiles(dirPath) {
2518
+ for (const entry of readdirSync(dirPath, { withFileTypes: true })) {
2519
+ const fullPath = path.join(dirPath, entry.name);
2520
+ if (entry.isDirectory()) {
2521
+ yield* walkFontFiles(fullPath);
2522
+ } else if (entry.isFile()) {
2523
+ const ext = path.extname(entry.name).toLowerCase();
2524
+ if (FONT_EXTENSIONS.has(ext)) {
2525
+ yield fullPath;
2526
+ }
2527
+ }
2528
+ }
2529
+ }
2530
+ function readFontsFromDir(dirPath) {
2531
+ const out = {};
2532
+ for (const fullPath of walkFontFiles(dirPath)) {
2533
+ const file = path.basename(fullPath);
2534
+ const buf = readFileSync(fullPath);
2535
+ const bytes = new Uint8Array(buf);
2536
+ const basenameNoExt = file.replace(/\.[^.]+$/, "") || file;
2537
+ let family;
2538
+ try {
2539
+ const [font] = typr_default.parse(bytes);
2540
+ family = font?.name?.fontFamily ?? basenameNoExt;
2541
+ } catch {
2542
+ family = basenameNoExt;
2543
+ }
2544
+ if (!family) continue;
2545
+ const existing = out[family];
2546
+ if (existing === void 0) {
2547
+ out[family] = [bytes];
2548
+ } else {
2549
+ existing.push(bytes);
2550
+ }
2551
+ }
2552
+ return out;
2553
+ }
77
2554
  function exportAllOutputBasename(nodeId, suffix, format) {
78
2555
  const ext = EXT_BY_FORMAT[format] ?? "png";
79
2556
  const safeId = sanitizeForFilename(nodeId);
@@ -81,17 +2558,28 @@ function exportAllOutputBasename(nodeId, suffix, format) {
81
2558
  const name = safeSuffix ? `${safeId}_${safeSuffix}` : safeId;
82
2559
  return `${name}.${ext}`;
83
2560
  }
84
- async function runExportAll(documentPath, outDir, imagesDir, skipDefaultFonts) {
2561
+ async function runExportAll(documentPath, outDir, imagesDir, fontsDir, skipDefaultFonts) {
85
2562
  const isFig = documentPath.toLowerCase().endsWith(".fig");
86
2563
  let document;
87
2564
  let items;
88
2565
  let rendererOptions = {};
89
2566
  if (isFig) {
90
- const bytes = new Uint8Array(readFileSync(documentPath));
91
- const figFile = iofigma.kiwi.parseFile(bytes);
2567
+ const stat = statSync(documentPath);
2568
+ const useStreaming = stat.size >= LARGE_FILE_THRESHOLD;
2569
+ let figFile;
2570
+ if (useStreaming) {
2571
+ const stream = createReadStream(documentPath, {
2572
+ highWaterMark: 1024 * 1024
2573
+ });
2574
+ figFile = await iofigma.kiwi.parseFileFromStream(stream);
2575
+ document = new FigmaDocument(figFile);
2576
+ } else {
2577
+ const bytes = new Uint8Array(readFileSync(documentPath));
2578
+ figFile = iofigma.kiwi.parseFile(bytes);
2579
+ document = new FigmaDocument(bytes);
2580
+ }
92
2581
  const restDoc = figFileToRestLikeDocument(figFile);
93
2582
  items = collectExportsFromDocument(restDoc);
94
- document = new FigmaDocument(bytes);
95
2583
  const imagesMap = iofigma.kiwi.extractImages(figFile.zip_files);
96
2584
  const images = {};
97
2585
  imagesMap.forEach((imgBytes, ref) => {
@@ -107,9 +2595,18 @@ async function runExportAll(documentPath, outDir, imagesDir, skipDefaultFonts) {
107
2595
  document.payload
108
2596
  );
109
2597
  if (imagesDir) {
110
- rendererOptions = { images: readImagesFromDir(imagesDir) };
2598
+ rendererOptions = {
2599
+ ...rendererOptions,
2600
+ images: readImagesFromDir(imagesDir)
2601
+ };
111
2602
  }
112
2603
  }
2604
+ if (fontsDir) {
2605
+ rendererOptions = {
2606
+ ...rendererOptions,
2607
+ fonts: readFontsFromDir(fontsDir)
2608
+ };
2609
+ }
113
2610
  if (skipDefaultFonts || process.env.REFIG_SKIP_DEFAULT_FONTS === "1") {
114
2611
  rendererOptions = { ...rendererOptions, loadFigmaDefaultFonts: false };
115
2612
  }
@@ -146,8 +2643,33 @@ async function runSingleNode(documentPath, nodeId, outPath, opts) {
146
2643
  throw new Error(`Unsupported --format "${format}"`);
147
2644
  }
148
2645
  const isJson = documentPath.toLowerCase().endsWith(".json");
149
- const document = isJson ? new FigmaDocument(JSON.parse(readFileSync(documentPath, "utf8"))) : new FigmaDocument(new Uint8Array(readFileSync(documentPath)));
150
- const rendererOptions = isJson && opts.imagesDir ? { images: readImagesFromDir(opts.imagesDir) } : {};
2646
+ let document;
2647
+ if (isJson) {
2648
+ document = new FigmaDocument(
2649
+ JSON.parse(readFileSync(documentPath, "utf8"))
2650
+ );
2651
+ } else {
2652
+ const isFig = documentPath.toLowerCase().endsWith(".fig");
2653
+ const useStreaming = isFig && statSync(documentPath).size >= LARGE_FILE_THRESHOLD;
2654
+ if (useStreaming) {
2655
+ const stream = createReadStream(documentPath, {
2656
+ highWaterMark: 1024 * 1024
2657
+ });
2658
+ const figFile = await iofigma.kiwi.parseFileFromStream(stream);
2659
+ document = new FigmaDocument(figFile);
2660
+ } else {
2661
+ document = new FigmaDocument(
2662
+ new Uint8Array(readFileSync(documentPath))
2663
+ );
2664
+ }
2665
+ }
2666
+ const rendererOptions = {};
2667
+ if (isJson && opts.imagesDir) {
2668
+ rendererOptions.images = readImagesFromDir(opts.imagesDir);
2669
+ }
2670
+ if (opts.fontsDir) {
2671
+ rendererOptions.fonts = readFontsFromDir(opts.fontsDir);
2672
+ }
151
2673
  if (opts.skipDefaultFonts || process.env.REFIG_SKIP_DEFAULT_FONTS === "1") {
152
2674
  rendererOptions.loadFigmaDefaultFonts = false;
153
2675
  }
@@ -174,19 +2696,22 @@ async function main() {
174
2696
  "Headless Figma renderer \u2014 render .fig and REST API JSON to PNG/JPEG/WebP/PDF/SVG"
175
2697
  ).argument(
176
2698
  "<input>",
177
- "Path to .fig, JSON file (REST API response), or directory containing document.json (and optionally images/)"
178
- ).requiredOption(
2699
+ "Path to .fig, JSON file (REST API response), or directory containing document.json (and optionally images/, fonts/)"
2700
+ ).option(
179
2701
  "--out <path>",
180
- "Output file path (single node) or output directory (--export-all)"
2702
+ "Output file path (single node) or output directory (--export-all); when omitted, uses OS temp directory (valid with --export-all or with both --format and --node)"
181
2703
  ).option(
182
2704
  "--images <dir>",
183
2705
  "Directory of image files for REST API document (optional; not used if <input> is a dir with images/)"
2706
+ ).option(
2707
+ "--fonts <dir>",
2708
+ "Directory of font files (TTF/OTF) for custom fonts (optional; not used if <input> is a dir with fonts/)"
184
2709
  ).option(
185
2710
  "--node <id>",
186
2711
  "Figma node ID to render (required unless --export-all)"
187
2712
  ).option(
188
2713
  "--export-all",
189
- "Export every node that has exportSettings (REST JSON only)"
2714
+ "Export every node that has exportSettings (REST JSON or .fig)"
190
2715
  ).option(
191
2716
  "--format <fmt>",
192
2717
  "png | jpeg | webp | pdf | svg (single-node only; default: from --out extension)"
@@ -199,32 +2724,35 @@ async function main() {
199
2724
  const exportAll = options.exportAll === true;
200
2725
  const nodeId = String(options.node ?? "").trim();
201
2726
  const explicitImagesDir = typeof options.images === "string" ? options.images : void 0;
202
- if (!outPath) {
203
- program.error("--out is required");
204
- }
205
- const { documentPath, imagesDir, isRestJson } = resolveInput(
2727
+ const explicitFontsDir = typeof options.fonts === "string" ? options.fonts : void 0;
2728
+ const { documentPath, imagesDir, fontsDir } = resolveInput(
206
2729
  input.trim(),
207
- explicitImagesDir
2730
+ explicitImagesDir,
2731
+ explicitFontsDir
208
2732
  );
209
2733
  if (exportAll) {
210
2734
  if (nodeId) {
211
2735
  program.error("--node must not be used with --export-all");
212
2736
  }
213
- const outDir = path.resolve(outPath);
214
- if (existsSync(outDir)) {
215
- const stat = statSync(outDir);
216
- if (!stat.isDirectory()) {
217
- program.error(
218
- "--out must be a directory when using --export-all"
219
- );
2737
+ const outDir = outPath ? (() => {
2738
+ const resolved = path.resolve(outPath);
2739
+ if (existsSync(resolved)) {
2740
+ const stat = statSync(resolved);
2741
+ if (!stat.isDirectory()) {
2742
+ program.error(
2743
+ "--out must be a directory when using --export-all"
2744
+ );
2745
+ }
2746
+ } else {
2747
+ mkdirSync(resolved, { recursive: true });
220
2748
  }
221
- } else {
222
- mkdirSync(outDir, { recursive: true });
223
- }
2749
+ return resolved;
2750
+ })() : mkdtempSync(path.join(tmpdir(), "refig-export-"));
224
2751
  await runExportAll(
225
2752
  documentPath,
226
2753
  outDir,
227
2754
  imagesDir,
2755
+ fontsDir,
228
2756
  options.skipDefaultFonts === true
229
2757
  );
230
2758
  return;
@@ -235,12 +2763,33 @@ async function main() {
235
2763
  const width = Number(options.width ?? 1024);
236
2764
  const height = Number(options.height ?? 1024);
237
2765
  const scale = Number(options.scale ?? 1);
238
- await runSingleNode(documentPath, nodeId, path.resolve(outPath), {
239
- format: typeof options.format === "string" ? options.format : void 0,
2766
+ const formatOption = typeof options.format === "string" ? options.format : void 0;
2767
+ let singleOutPath;
2768
+ if (outPath) {
2769
+ singleOutPath = path.resolve(outPath);
2770
+ } else {
2771
+ if (!formatOption) {
2772
+ program.error(
2773
+ "When --out is omitted, both --node and --format are required"
2774
+ );
2775
+ }
2776
+ const format = formatOption.toLowerCase();
2777
+ if (!FORMAT_SET.has(format)) {
2778
+ program.error(`Unsupported --format "${format}"`);
2779
+ }
2780
+ const ext = EXT_BY_FORMAT[format] ?? "png";
2781
+ singleOutPath = path.join(
2782
+ tmpdir(),
2783
+ `refig-${sanitizeForFilename(nodeId)}.${ext}`
2784
+ );
2785
+ }
2786
+ await runSingleNode(documentPath, nodeId, singleOutPath, {
2787
+ format: formatOption,
240
2788
  width,
241
2789
  height,
242
2790
  scale,
243
2791
  imagesDir,
2792
+ fontsDir,
244
2793
  skipDefaultFonts: options.skipDefaultFonts === true
245
2794
  });
246
2795
  }