@shotstack/shotstack-canvas 1.0.7 → 1.0.8
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/entry.node.cjs +49 -24
- package/dist/entry.node.cjs.map +1 -1
- package/dist/entry.node.d.cts +1 -0
- package/dist/entry.node.d.ts +1 -0
- package/dist/entry.node.js +49 -24
- package/dist/entry.node.js.map +1 -1
- package/dist/entry.web.d.ts +1 -0
- package/dist/entry.web.js +49 -24
- package/dist/entry.web.js.map +1 -1
- package/package.json +1 -1
package/dist/entry.node.js
CHANGED
|
@@ -150,14 +150,33 @@ var FontRegistry = class {
|
|
|
150
150
|
fonts = /* @__PURE__ */ new Map();
|
|
151
151
|
blobs = /* @__PURE__ */ new Map();
|
|
152
152
|
wasmBaseURL;
|
|
153
|
+
initPromise;
|
|
153
154
|
constructor(wasmBaseURL) {
|
|
154
155
|
this.wasmBaseURL = wasmBaseURL;
|
|
155
156
|
}
|
|
156
157
|
async init() {
|
|
157
|
-
if (
|
|
158
|
+
if (this.initPromise) {
|
|
159
|
+
await this.initPromise;
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (this.hb) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
this.initPromise = this._doInit();
|
|
166
|
+
await this.initPromise;
|
|
167
|
+
}
|
|
168
|
+
async _doInit() {
|
|
169
|
+
try {
|
|
170
|
+
this.hb = await initHB(this.wasmBaseURL);
|
|
171
|
+
} catch (error) {
|
|
172
|
+
this.initPromise = void 0;
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
158
175
|
}
|
|
159
|
-
getHB() {
|
|
160
|
-
if (!this.hb)
|
|
176
|
+
async getHB() {
|
|
177
|
+
if (!this.hb) {
|
|
178
|
+
await this.init();
|
|
179
|
+
}
|
|
161
180
|
return this.hb;
|
|
162
181
|
}
|
|
163
182
|
key(desc) {
|
|
@@ -176,23 +195,24 @@ var FontRegistry = class {
|
|
|
176
195
|
this.faces.set(k, face);
|
|
177
196
|
this.fonts.set(k, font);
|
|
178
197
|
}
|
|
179
|
-
getFont(desc) {
|
|
198
|
+
async getFont(desc) {
|
|
199
|
+
if (!this.hb) await this.init();
|
|
180
200
|
const k = this.key(desc);
|
|
181
201
|
const f = this.fonts.get(k);
|
|
182
202
|
if (!f) throw new Error(`Font not registered for ${k}`);
|
|
183
203
|
return f;
|
|
184
204
|
}
|
|
185
|
-
getFace(desc) {
|
|
205
|
+
async getFace(desc) {
|
|
206
|
+
if (!this.hb) await this.init();
|
|
186
207
|
const k = this.key(desc);
|
|
187
208
|
return this.faces.get(k);
|
|
188
209
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const face = this.getFace(desc);
|
|
210
|
+
async getUnitsPerEm(desc) {
|
|
211
|
+
const face = await this.getFace(desc);
|
|
192
212
|
return face?.upem || 1e3;
|
|
193
213
|
}
|
|
194
|
-
glyphPath(desc, glyphId) {
|
|
195
|
-
const font = this.getFont(desc);
|
|
214
|
+
async glyphPath(desc, glyphId) {
|
|
215
|
+
const font = await this.getFont(desc);
|
|
196
216
|
const path = font.glyphToPath(glyphId);
|
|
197
217
|
return path && path !== "" ? path : "M 0 0";
|
|
198
218
|
}
|
|
@@ -203,6 +223,8 @@ var FontRegistry = class {
|
|
|
203
223
|
this.fonts.clear();
|
|
204
224
|
this.faces.clear();
|
|
205
225
|
this.blobs.clear();
|
|
226
|
+
this.hb = void 0;
|
|
227
|
+
this.initPromise = void 0;
|
|
206
228
|
}
|
|
207
229
|
};
|
|
208
230
|
|
|
@@ -223,13 +245,13 @@ var LayoutEngine = class {
|
|
|
223
245
|
return t;
|
|
224
246
|
}
|
|
225
247
|
}
|
|
226
|
-
shapeFull(text, desc) {
|
|
227
|
-
const hb = this.fonts.getHB();
|
|
248
|
+
async shapeFull(text, desc) {
|
|
249
|
+
const hb = await this.fonts.getHB();
|
|
228
250
|
const buffer = hb.createBuffer();
|
|
229
251
|
buffer.addText(text);
|
|
230
252
|
buffer.guessSegmentProperties();
|
|
231
|
-
const font = this.fonts.getFont(desc);
|
|
232
|
-
const face = this.fonts.getFace(desc);
|
|
253
|
+
const font = await this.fonts.getFont(desc);
|
|
254
|
+
const face = await this.fonts.getFace(desc);
|
|
233
255
|
const upem = face?.upem || 1e3;
|
|
234
256
|
font.setScale(upem, upem);
|
|
235
257
|
hb.shape(font, buffer);
|
|
@@ -237,17 +259,17 @@ var LayoutEngine = class {
|
|
|
237
259
|
buffer.destroy();
|
|
238
260
|
return result;
|
|
239
261
|
}
|
|
240
|
-
layout(params) {
|
|
262
|
+
async layout(params) {
|
|
241
263
|
const { textTransform, desc, fontSize, letterSpacing, width } = params;
|
|
242
264
|
const input = this.transformText(params.text, textTransform);
|
|
243
265
|
if (!input || input.length === 0) {
|
|
244
266
|
return [];
|
|
245
267
|
}
|
|
246
|
-
const shaped = this.shapeFull(input, desc);
|
|
247
|
-
const face = this.fonts.getFace(desc);
|
|
268
|
+
const shaped = await this.shapeFull(input, desc);
|
|
269
|
+
const face = await this.fonts.getFace(desc);
|
|
248
270
|
const upem = face?.upem || 1e3;
|
|
249
271
|
const scale = fontSize / upem;
|
|
250
|
-
const glyphs = shaped.map((g
|
|
272
|
+
const glyphs = shaped.map((g) => {
|
|
251
273
|
const charIndex = g.cl;
|
|
252
274
|
let char;
|
|
253
275
|
if (charIndex >= 0 && charIndex < input.length) {
|
|
@@ -351,7 +373,7 @@ function decorationGeometry(kind, p) {
|
|
|
351
373
|
}
|
|
352
374
|
|
|
353
375
|
// src/core/drawops.ts
|
|
354
|
-
function buildDrawOps(p) {
|
|
376
|
+
async function buildDrawOps(p) {
|
|
355
377
|
const ops = [];
|
|
356
378
|
ops.push({
|
|
357
379
|
op: "BeginFrame",
|
|
@@ -362,7 +384,7 @@ function buildDrawOps(p) {
|
|
|
362
384
|
bg: p.background ? { color: p.background.color, opacity: p.background.opacity, radius: p.background.borderRadius } : void 0
|
|
363
385
|
});
|
|
364
386
|
if (p.lines.length === 0) return ops;
|
|
365
|
-
const upem = Math.max(1, p.getUnitsPerEm
|
|
387
|
+
const upem = Math.max(1, await p.getUnitsPerEm());
|
|
366
388
|
const scale = p.font.size / upem;
|
|
367
389
|
const blockHeight = p.lines[p.lines.length - 1].y;
|
|
368
390
|
let blockY;
|
|
@@ -398,7 +420,7 @@ function buildDrawOps(p) {
|
|
|
398
420
|
let xCursor = lineX;
|
|
399
421
|
const baselineY = blockY + line.y - p.font.size;
|
|
400
422
|
for (const glyph of line.glyphs) {
|
|
401
|
-
const path = p.glyphPathProvider(glyph.id);
|
|
423
|
+
const path = await p.glyphPathProvider(glyph.id);
|
|
402
424
|
if (!path || path === "M 0 0") {
|
|
403
425
|
xCursor += glyph.xAdvance;
|
|
404
426
|
continue;
|
|
@@ -1390,6 +1412,7 @@ async function createTextEngine(opts = {}) {
|
|
|
1390
1412
|
const fonts = new FontRegistry(wasmBaseURL);
|
|
1391
1413
|
const layout = new LayoutEngine(fonts);
|
|
1392
1414
|
const videoGenerator = new VideoGenerator();
|
|
1415
|
+
await fonts.init();
|
|
1393
1416
|
async function ensureFonts(asset) {
|
|
1394
1417
|
if (asset.customFonts) {
|
|
1395
1418
|
for (const cf of asset.customFonts) {
|
|
@@ -1431,7 +1454,7 @@ async function createTextEngine(opts = {}) {
|
|
|
1431
1454
|
async renderFrame(asset, tSeconds) {
|
|
1432
1455
|
const main = await ensureFonts(asset);
|
|
1433
1456
|
const desc = { family: main.family, weight: `${main.weight}`, style: main.style };
|
|
1434
|
-
const lines = layout.layout({
|
|
1457
|
+
const lines = await layout.layout({
|
|
1435
1458
|
text: asset.text,
|
|
1436
1459
|
width: asset.width ?? width,
|
|
1437
1460
|
letterSpacing: asset.style?.letterSpacing ?? 0,
|
|
@@ -1444,7 +1467,7 @@ async function createTextEngine(opts = {}) {
|
|
|
1444
1467
|
const canvasW = asset.width ?? width;
|
|
1445
1468
|
const canvasH = asset.height ?? height;
|
|
1446
1469
|
const canvasPR = asset.pixelRatio ?? pixelRatio;
|
|
1447
|
-
const ops0 = buildDrawOps({
|
|
1470
|
+
const ops0 = await buildDrawOps({
|
|
1448
1471
|
canvas: { width: canvasW, height: canvasH, pixelRatio: canvasPR },
|
|
1449
1472
|
textRect,
|
|
1450
1473
|
lines,
|
|
@@ -1466,7 +1489,6 @@ async function createTextEngine(opts = {}) {
|
|
|
1466
1489
|
align: asset.align ?? { horizontal: "left", vertical: "middle" },
|
|
1467
1490
|
background: asset.background,
|
|
1468
1491
|
glyphPathProvider: (gid) => fonts.glyphPath(desc, gid),
|
|
1469
|
-
/** NEW: provide UPEM so drawops can compute scale */
|
|
1470
1492
|
getUnitsPerEm: () => fonts.getUnitsPerEm(desc)
|
|
1471
1493
|
});
|
|
1472
1494
|
const ops = applyAnimation(ops0, lines, {
|
|
@@ -1502,6 +1524,9 @@ async function createTextEngine(opts = {}) {
|
|
|
1502
1524
|
return this.renderFrame(asset, time);
|
|
1503
1525
|
};
|
|
1504
1526
|
await videoGenerator.generateVideo(frameGenerator, finalOptions);
|
|
1527
|
+
},
|
|
1528
|
+
destroy() {
|
|
1529
|
+
fonts.destroy();
|
|
1505
1530
|
}
|
|
1506
1531
|
};
|
|
1507
1532
|
}
|