@shotstack/shotstack-canvas 1.6.2 → 1.6.3
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 +41 -45
- package/dist/entry.node.js +41 -45
- package/dist/entry.web.js +28 -41
- package/package.json +1 -1
package/dist/entry.node.cjs
CHANGED
|
@@ -196,13 +196,11 @@ function bufferToArrayBuffer(buffer) {
|
|
|
196
196
|
var DEFAULT_WASM_URL = "https://shotstack-ingest-api-dev-sources.s3.ap-southeast-2.amazonaws.com/euo5r93oyr/zzz01k9h-yycyx-2x2y6-qx9bj-7n567b/source.wasm";
|
|
197
197
|
async function fetchWasmFromUrl(url) {
|
|
198
198
|
try {
|
|
199
|
-
console.log(`\u{1F310} Fetching WASM from URL: ${url}`);
|
|
200
199
|
const response = await fetch(url);
|
|
201
200
|
if (response.ok) {
|
|
202
201
|
const arrayBuffer = await response.arrayBuffer();
|
|
203
202
|
const bytes = new Uint8Array(arrayBuffer);
|
|
204
203
|
if (bytes.length >= 4 && bytes[0] === 0 && bytes[1] === 97 && bytes[2] === 115 && bytes[3] === 109) {
|
|
205
|
-
console.log(`\u2705 Fetched WASM from URL (${bytes.length} bytes)`);
|
|
206
204
|
return arrayBuffer;
|
|
207
205
|
} else {
|
|
208
206
|
console.error(`\u274C Invalid WASM magic number from URL: ${url}`);
|
|
@@ -250,21 +248,17 @@ async function loadWasmNode() {
|
|
|
250
248
|
"/var/task/node_modules/harfbuzzjs/hb.wasm",
|
|
251
249
|
"/var/task/node_modules/@shotstack/shotstack-canvas/assets/wasm/hb.wasm"
|
|
252
250
|
);
|
|
253
|
-
console.log(`\u{1F50D} Searching for WASM in ${candidates.length} local paths...`);
|
|
254
251
|
for (const candidate of candidates) {
|
|
255
252
|
try {
|
|
256
253
|
const buffer = await readFile2(candidate);
|
|
257
|
-
console.log(`\u2705 Found WASM at: ${candidate}`);
|
|
258
254
|
return bufferToArrayBuffer(buffer);
|
|
259
255
|
} catch {
|
|
260
256
|
continue;
|
|
261
257
|
}
|
|
262
258
|
}
|
|
263
|
-
console.log("\u{1F4C2} Local WASM not found, fetching from URL...");
|
|
264
259
|
return await fetchWasmFromUrl(DEFAULT_WASM_URL);
|
|
265
260
|
} catch (err) {
|
|
266
261
|
console.error("Error in loadWasmNode:", err);
|
|
267
|
-
console.log("\u26A0\uFE0F Error during local search, falling back to URL...");
|
|
268
262
|
return await fetchWasmFromUrl(DEFAULT_WASM_URL);
|
|
269
263
|
}
|
|
270
264
|
}
|
|
@@ -272,13 +266,11 @@ async function loadWasmWeb(wasmBaseURL) {
|
|
|
272
266
|
try {
|
|
273
267
|
if (wasmBaseURL) {
|
|
274
268
|
const url = wasmBaseURL.endsWith(".wasm") ? wasmBaseURL : wasmBaseURL.endsWith("/") ? `${wasmBaseURL}hb.wasm` : `${wasmBaseURL}/hb.wasm`;
|
|
275
|
-
console.log(`Fetching WASM from: ${url}`);
|
|
276
269
|
const response = await fetch(url);
|
|
277
270
|
if (response.ok) {
|
|
278
271
|
const arrayBuffer = await response.arrayBuffer();
|
|
279
272
|
const bytes = new Uint8Array(arrayBuffer);
|
|
280
273
|
if (bytes.length >= 4 && bytes[0] === 0 && bytes[1] === 97 && bytes[2] === 115 && bytes[3] === 109) {
|
|
281
|
-
console.log(`\u2705 Valid WASM binary loaded (${bytes.length} bytes)`);
|
|
282
274
|
return arrayBuffer;
|
|
283
275
|
}
|
|
284
276
|
}
|
|
@@ -294,7 +286,6 @@ function setupWasmInterceptors(wasmBinary) {
|
|
|
294
286
|
window.fetch = function(input, init) {
|
|
295
287
|
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
296
288
|
if (url.includes("hb.wasm") || url.endsWith(".wasm") && !url.includes("source.wasm")) {
|
|
297
|
-
console.log(`\u{1F504} Intercepted fetch for: ${url}`);
|
|
298
289
|
return Promise.resolve(
|
|
299
290
|
new Response(wasmBinary.slice(0), {
|
|
300
291
|
status: 200,
|
|
@@ -310,13 +301,9 @@ function setupWasmInterceptors(wasmBinary) {
|
|
|
310
301
|
};
|
|
311
302
|
const originalInstantiate = WebAssembly.instantiate;
|
|
312
303
|
WebAssembly.instantiate = async function(bufferSourceOrModule, importObject) {
|
|
313
|
-
console.log(
|
|
314
|
-
`\u{1F504} WebAssembly.instantiate called, type: ${bufferSourceOrModule instanceof WebAssembly.Module ? "Module" : "BufferSource"}`
|
|
315
|
-
);
|
|
316
304
|
if (bufferSourceOrModule instanceof WebAssembly.Module) {
|
|
317
305
|
return originalInstantiate.call(WebAssembly, bufferSourceOrModule, importObject);
|
|
318
306
|
}
|
|
319
|
-
console.log(`\u{1F504} Intercepted WebAssembly.instantiate, using pre-loaded WASM binary`);
|
|
320
307
|
const module2 = await WebAssembly.compile(wasmBinary);
|
|
321
308
|
const instance = await originalInstantiate.call(
|
|
322
309
|
WebAssembly,
|
|
@@ -332,14 +319,12 @@ function setupWasmInterceptors(wasmBinary) {
|
|
|
332
319
|
const response = await source;
|
|
333
320
|
const url = response.url || "";
|
|
334
321
|
if (url.includes("hb.wasm") || url.endsWith(".wasm") && !url.includes("source.wasm")) {
|
|
335
|
-
console.log(`\u{1F504} Intercepted instantiateStreaming for: ${url}`);
|
|
336
322
|
const module2 = await WebAssembly.compile(wasmBinary);
|
|
337
323
|
const instance = await WebAssembly.instantiate(module2, importObject);
|
|
338
324
|
return { module: module2, instance };
|
|
339
325
|
}
|
|
340
326
|
return originalInstantiateStreaming.call(WebAssembly, response, importObject);
|
|
341
327
|
} catch (err) {
|
|
342
|
-
console.log("\u{1F504} instantiateStreaming failed, using pre-loaded binary");
|
|
343
328
|
const module2 = await WebAssembly.compile(wasmBinary);
|
|
344
329
|
const instance = await WebAssembly.instantiate(module2, importObject);
|
|
345
330
|
return { module: module2, instance };
|
|
@@ -359,33 +344,25 @@ async function initHB(wasmBaseURL) {
|
|
|
359
344
|
if (!wasmBinary) {
|
|
360
345
|
throw new Error("Failed to load WASM binary from any source");
|
|
361
346
|
}
|
|
362
|
-
console.log(`\u2705 WASM binary loaded successfully (${wasmBinary.byteLength} bytes)`);
|
|
363
347
|
if (!isNode()) {
|
|
364
348
|
setupWasmInterceptors(wasmBinary);
|
|
365
349
|
window.Module = {
|
|
366
350
|
wasmBinary,
|
|
367
351
|
locateFile: (path) => {
|
|
368
|
-
console.log(`\u{1F50D} locateFile called for: ${path}`);
|
|
369
352
|
return path;
|
|
370
353
|
}
|
|
371
354
|
};
|
|
372
|
-
console.log(`\u{1F30D} Set global Module.wasmBinary (${wasmBinary.byteLength} bytes)`);
|
|
373
355
|
}
|
|
374
|
-
console.log("\u{1F504} Importing harfbuzzjs/hb.js (factory)");
|
|
375
356
|
const hbModule = await import("harfbuzzjs/hb.js");
|
|
376
357
|
const hbFactory = hbModule.default || hbModule;
|
|
377
|
-
console.log("\u{1F504} Calling hb factory with wasmBinary");
|
|
378
358
|
const hbInstance = await hbFactory({ wasmBinary });
|
|
379
|
-
console.log("\u{1F504} Importing harfbuzzjs/hbjs.js (wrapper)");
|
|
380
359
|
const hbjsModule = await import("harfbuzzjs/hbjs.js");
|
|
381
360
|
const hbjsWrapper = hbjsModule.default || hbjsModule;
|
|
382
|
-
console.log("\u{1F504} Wrapping hb instance");
|
|
383
361
|
const hb = hbjsWrapper(hbInstance);
|
|
384
362
|
if (!hb || typeof hb.createBuffer !== "function" || typeof hb.createFont !== "function") {
|
|
385
363
|
throw new Error("Failed to initialize HarfBuzz: unexpected export shape from 'harfbuzzjs'.");
|
|
386
364
|
}
|
|
387
365
|
hbSingleton = hb;
|
|
388
|
-
console.log("\u2705 HarfBuzz initialized successfully");
|
|
389
366
|
return hbSingleton;
|
|
390
367
|
} catch (err) {
|
|
391
368
|
console.error("Failed to initialize HarfBuzz:", err);
|
|
@@ -896,7 +873,6 @@ async function buildDrawOps(p) {
|
|
|
896
873
|
pixelRatio: p.canvas.pixelRatio,
|
|
897
874
|
clear: true,
|
|
898
875
|
bg: void 0
|
|
899
|
-
// Background will be drawn as a separate layer with proper padding/border
|
|
900
876
|
});
|
|
901
877
|
if (p.lines.length === 0) return ops;
|
|
902
878
|
const upem = Math.max(1, await p.getUnitsPerEm());
|
|
@@ -1024,7 +1000,12 @@ async function buildDrawOps(p) {
|
|
|
1024
1000
|
}
|
|
1025
1001
|
}
|
|
1026
1002
|
if (gMinX !== Infinity) {
|
|
1027
|
-
const gbox = {
|
|
1003
|
+
const gbox = {
|
|
1004
|
+
x: gMinX,
|
|
1005
|
+
y: gMinY,
|
|
1006
|
+
w: Math.max(1, gMaxX - gMinX),
|
|
1007
|
+
h: Math.max(1, gMaxY - gMinY)
|
|
1008
|
+
};
|
|
1028
1009
|
for (const op of textOps) {
|
|
1029
1010
|
if (op.op === "FillPath" && !op.isShadow) {
|
|
1030
1011
|
op.gradientBBox = gbox;
|
|
@@ -1032,14 +1013,16 @@ async function buildDrawOps(p) {
|
|
|
1032
1013
|
}
|
|
1033
1014
|
}
|
|
1034
1015
|
if (p.background || p.border) {
|
|
1035
|
-
const
|
|
1036
|
-
const
|
|
1037
|
-
const bgWidth = p.canvas.width;
|
|
1038
|
-
const bgHeight = p.canvas.height;
|
|
1016
|
+
const contentWidth = p.contentRect?.width ?? p.canvas.width;
|
|
1017
|
+
const contentHeight = p.contentRect?.height ?? p.canvas.height;
|
|
1039
1018
|
const borderWidth2 = p.border?.width ?? 0;
|
|
1040
1019
|
const borderRadius = p.border?.radius ?? 0;
|
|
1041
1020
|
const halfBorder = borderWidth2 / 2;
|
|
1042
|
-
const
|
|
1021
|
+
const canvasCenterX = p.canvas.width / 2;
|
|
1022
|
+
const canvasCenterY = p.canvas.height / 2;
|
|
1023
|
+
const bgX = canvasCenterX - contentWidth / 2;
|
|
1024
|
+
const bgY = canvasCenterY - contentHeight / 2;
|
|
1025
|
+
const maxRadius = Math.min(contentWidth - borderWidth2, contentHeight - borderWidth2) / 2;
|
|
1043
1026
|
const outerRadius = Math.min(borderRadius, maxRadius);
|
|
1044
1027
|
const innerRadius = Math.max(0, outerRadius - halfBorder);
|
|
1045
1028
|
if (p.background?.color) {
|
|
@@ -1047,8 +1030,8 @@ async function buildDrawOps(p) {
|
|
|
1047
1030
|
op: "Rectangle",
|
|
1048
1031
|
x: bgX + borderWidth2,
|
|
1049
1032
|
y: bgY + borderWidth2,
|
|
1050
|
-
width:
|
|
1051
|
-
height:
|
|
1033
|
+
width: contentWidth - borderWidth2 * 2,
|
|
1034
|
+
height: contentHeight - borderWidth2 * 2,
|
|
1052
1035
|
fill: { kind: "solid", color: p.background.color, opacity: p.background.opacity },
|
|
1053
1036
|
borderRadius: innerRadius
|
|
1054
1037
|
});
|
|
@@ -1058,8 +1041,8 @@ async function buildDrawOps(p) {
|
|
|
1058
1041
|
op: "RectangleStroke",
|
|
1059
1042
|
x: bgX + halfBorder,
|
|
1060
1043
|
y: bgY + halfBorder,
|
|
1061
|
-
width:
|
|
1062
|
-
height:
|
|
1044
|
+
width: contentWidth - borderWidth2,
|
|
1045
|
+
height: contentHeight - borderWidth2,
|
|
1063
1046
|
stroke: {
|
|
1064
1047
|
width: p.border.width,
|
|
1065
1048
|
color: p.border.color,
|
|
@@ -2494,9 +2477,15 @@ async function createTextEngine(opts = {}) {
|
|
|
2494
2477
|
emojiAvailable = true;
|
|
2495
2478
|
} catch {
|
|
2496
2479
|
}
|
|
2480
|
+
const padding2 = asset.padding ? typeof asset.padding === "number" ? {
|
|
2481
|
+
top: asset.padding,
|
|
2482
|
+
right: asset.padding,
|
|
2483
|
+
bottom: asset.padding,
|
|
2484
|
+
left: asset.padding
|
|
2485
|
+
} : asset.padding : { top: 0, right: 0, bottom: 0, left: 0 };
|
|
2497
2486
|
lines = await layout.layout({
|
|
2498
2487
|
text: asset.text,
|
|
2499
|
-
width: asset.width ?? width,
|
|
2488
|
+
width: (asset.width ?? width) - padding2.left - padding2.right,
|
|
2500
2489
|
letterSpacing: asset.style?.letterSpacing ?? 0,
|
|
2501
2490
|
fontSize: main.size,
|
|
2502
2491
|
lineHeight: asset.style?.lineHeight ?? 1.2,
|
|
@@ -2509,23 +2498,31 @@ async function createTextEngine(opts = {}) {
|
|
|
2509
2498
|
`Failed to layout text: ${err instanceof Error ? err.message : String(err)}`
|
|
2510
2499
|
);
|
|
2511
2500
|
}
|
|
2512
|
-
const padding = asset.padding ? typeof asset.padding === "number" ? {
|
|
2501
|
+
const padding = asset.padding ? typeof asset.padding === "number" ? {
|
|
2502
|
+
top: asset.padding,
|
|
2503
|
+
right: asset.padding,
|
|
2504
|
+
bottom: asset.padding,
|
|
2505
|
+
left: asset.padding
|
|
2506
|
+
} : asset.padding : { top: 0, right: 0, bottom: 0, left: 0 };
|
|
2507
|
+
const borderWidth = asset.border?.width ?? 0;
|
|
2508
|
+
const canvasW = (asset.width ?? width) + borderWidth * 2;
|
|
2509
|
+
const canvasH = (asset.height ?? height) + borderWidth * 2;
|
|
2510
|
+
const canvasPR = pixelRatio;
|
|
2513
2511
|
const textRect = {
|
|
2514
2512
|
x: 0,
|
|
2515
2513
|
y: 0,
|
|
2516
|
-
width: asset.width ?? width,
|
|
2517
|
-
height: asset.height ?? height
|
|
2514
|
+
width: (asset.width ?? width) - padding.left - padding.right,
|
|
2515
|
+
height: (asset.height ?? height) - padding.top - padding.bottom
|
|
2518
2516
|
};
|
|
2519
|
-
const
|
|
2520
|
-
const
|
|
2521
|
-
const canvasH = (asset.height ?? height) + padding.top + padding.bottom + borderWidth * 2;
|
|
2522
|
-
const canvasPR = pixelRatio;
|
|
2517
|
+
const contentW = canvasW;
|
|
2518
|
+
const contentH = canvasH;
|
|
2523
2519
|
let ops0;
|
|
2524
2520
|
try {
|
|
2525
2521
|
ops0 = await buildDrawOps({
|
|
2526
2522
|
canvas: { width: canvasW, height: canvasH, pixelRatio: canvasPR },
|
|
2527
2523
|
textRect,
|
|
2528
2524
|
lines,
|
|
2525
|
+
contentRect: { width: contentW, height: contentH },
|
|
2529
2526
|
font: {
|
|
2530
2527
|
family: main.family,
|
|
2531
2528
|
size: main.size,
|
|
@@ -2604,10 +2601,9 @@ async function createTextEngine(opts = {}) {
|
|
|
2604
2601
|
console.log(
|
|
2605
2602
|
`\u{1F3A8} Video settings: Animation=${hasAnimation}, Background=${hasBackground}, BorderRadius=${hasBorderRadius}, Alpha=${needsAlpha}`
|
|
2606
2603
|
);
|
|
2607
|
-
const padding = asset.padding ? typeof asset.padding === "number" ? { left: asset.padding, right: asset.padding, top: asset.padding, bottom: asset.padding } : asset.padding : { left: 0, right: 0, top: 0, bottom: 0 };
|
|
2608
2604
|
const borderWidth = asset.border?.width ?? 0;
|
|
2609
|
-
const canvasWidth = (asset.width ?? width) +
|
|
2610
|
-
const canvasHeight = (asset.height ?? height) +
|
|
2605
|
+
const canvasWidth = (asset.width ?? width) + borderWidth * 2;
|
|
2606
|
+
const canvasHeight = (asset.height ?? height) + borderWidth * 2;
|
|
2611
2607
|
const finalOptions = {
|
|
2612
2608
|
width: canvasWidth,
|
|
2613
2609
|
height: canvasHeight,
|
package/dist/entry.node.js
CHANGED
|
@@ -157,13 +157,11 @@ function bufferToArrayBuffer(buffer) {
|
|
|
157
157
|
var DEFAULT_WASM_URL = "https://shotstack-ingest-api-dev-sources.s3.ap-southeast-2.amazonaws.com/euo5r93oyr/zzz01k9h-yycyx-2x2y6-qx9bj-7n567b/source.wasm";
|
|
158
158
|
async function fetchWasmFromUrl(url) {
|
|
159
159
|
try {
|
|
160
|
-
console.log(`\u{1F310} Fetching WASM from URL: ${url}`);
|
|
161
160
|
const response = await fetch(url);
|
|
162
161
|
if (response.ok) {
|
|
163
162
|
const arrayBuffer = await response.arrayBuffer();
|
|
164
163
|
const bytes = new Uint8Array(arrayBuffer);
|
|
165
164
|
if (bytes.length >= 4 && bytes[0] === 0 && bytes[1] === 97 && bytes[2] === 115 && bytes[3] === 109) {
|
|
166
|
-
console.log(`\u2705 Fetched WASM from URL (${bytes.length} bytes)`);
|
|
167
165
|
return arrayBuffer;
|
|
168
166
|
} else {
|
|
169
167
|
console.error(`\u274C Invalid WASM magic number from URL: ${url}`);
|
|
@@ -211,21 +209,17 @@ async function loadWasmNode() {
|
|
|
211
209
|
"/var/task/node_modules/harfbuzzjs/hb.wasm",
|
|
212
210
|
"/var/task/node_modules/@shotstack/shotstack-canvas/assets/wasm/hb.wasm"
|
|
213
211
|
);
|
|
214
|
-
console.log(`\u{1F50D} Searching for WASM in ${candidates.length} local paths...`);
|
|
215
212
|
for (const candidate of candidates) {
|
|
216
213
|
try {
|
|
217
214
|
const buffer = await readFile2(candidate);
|
|
218
|
-
console.log(`\u2705 Found WASM at: ${candidate}`);
|
|
219
215
|
return bufferToArrayBuffer(buffer);
|
|
220
216
|
} catch {
|
|
221
217
|
continue;
|
|
222
218
|
}
|
|
223
219
|
}
|
|
224
|
-
console.log("\u{1F4C2} Local WASM not found, fetching from URL...");
|
|
225
220
|
return await fetchWasmFromUrl(DEFAULT_WASM_URL);
|
|
226
221
|
} catch (err) {
|
|
227
222
|
console.error("Error in loadWasmNode:", err);
|
|
228
|
-
console.log("\u26A0\uFE0F Error during local search, falling back to URL...");
|
|
229
223
|
return await fetchWasmFromUrl(DEFAULT_WASM_URL);
|
|
230
224
|
}
|
|
231
225
|
}
|
|
@@ -233,13 +227,11 @@ async function loadWasmWeb(wasmBaseURL) {
|
|
|
233
227
|
try {
|
|
234
228
|
if (wasmBaseURL) {
|
|
235
229
|
const url = wasmBaseURL.endsWith(".wasm") ? wasmBaseURL : wasmBaseURL.endsWith("/") ? `${wasmBaseURL}hb.wasm` : `${wasmBaseURL}/hb.wasm`;
|
|
236
|
-
console.log(`Fetching WASM from: ${url}`);
|
|
237
230
|
const response = await fetch(url);
|
|
238
231
|
if (response.ok) {
|
|
239
232
|
const arrayBuffer = await response.arrayBuffer();
|
|
240
233
|
const bytes = new Uint8Array(arrayBuffer);
|
|
241
234
|
if (bytes.length >= 4 && bytes[0] === 0 && bytes[1] === 97 && bytes[2] === 115 && bytes[3] === 109) {
|
|
242
|
-
console.log(`\u2705 Valid WASM binary loaded (${bytes.length} bytes)`);
|
|
243
235
|
return arrayBuffer;
|
|
244
236
|
}
|
|
245
237
|
}
|
|
@@ -255,7 +247,6 @@ function setupWasmInterceptors(wasmBinary) {
|
|
|
255
247
|
window.fetch = function(input, init) {
|
|
256
248
|
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
257
249
|
if (url.includes("hb.wasm") || url.endsWith(".wasm") && !url.includes("source.wasm")) {
|
|
258
|
-
console.log(`\u{1F504} Intercepted fetch for: ${url}`);
|
|
259
250
|
return Promise.resolve(
|
|
260
251
|
new Response(wasmBinary.slice(0), {
|
|
261
252
|
status: 200,
|
|
@@ -271,13 +262,9 @@ function setupWasmInterceptors(wasmBinary) {
|
|
|
271
262
|
};
|
|
272
263
|
const originalInstantiate = WebAssembly.instantiate;
|
|
273
264
|
WebAssembly.instantiate = async function(bufferSourceOrModule, importObject) {
|
|
274
|
-
console.log(
|
|
275
|
-
`\u{1F504} WebAssembly.instantiate called, type: ${bufferSourceOrModule instanceof WebAssembly.Module ? "Module" : "BufferSource"}`
|
|
276
|
-
);
|
|
277
265
|
if (bufferSourceOrModule instanceof WebAssembly.Module) {
|
|
278
266
|
return originalInstantiate.call(WebAssembly, bufferSourceOrModule, importObject);
|
|
279
267
|
}
|
|
280
|
-
console.log(`\u{1F504} Intercepted WebAssembly.instantiate, using pre-loaded WASM binary`);
|
|
281
268
|
const module = await WebAssembly.compile(wasmBinary);
|
|
282
269
|
const instance = await originalInstantiate.call(
|
|
283
270
|
WebAssembly,
|
|
@@ -293,14 +280,12 @@ function setupWasmInterceptors(wasmBinary) {
|
|
|
293
280
|
const response = await source;
|
|
294
281
|
const url = response.url || "";
|
|
295
282
|
if (url.includes("hb.wasm") || url.endsWith(".wasm") && !url.includes("source.wasm")) {
|
|
296
|
-
console.log(`\u{1F504} Intercepted instantiateStreaming for: ${url}`);
|
|
297
283
|
const module = await WebAssembly.compile(wasmBinary);
|
|
298
284
|
const instance = await WebAssembly.instantiate(module, importObject);
|
|
299
285
|
return { module, instance };
|
|
300
286
|
}
|
|
301
287
|
return originalInstantiateStreaming.call(WebAssembly, response, importObject);
|
|
302
288
|
} catch (err) {
|
|
303
|
-
console.log("\u{1F504} instantiateStreaming failed, using pre-loaded binary");
|
|
304
289
|
const module = await WebAssembly.compile(wasmBinary);
|
|
305
290
|
const instance = await WebAssembly.instantiate(module, importObject);
|
|
306
291
|
return { module, instance };
|
|
@@ -320,33 +305,25 @@ async function initHB(wasmBaseURL) {
|
|
|
320
305
|
if (!wasmBinary) {
|
|
321
306
|
throw new Error("Failed to load WASM binary from any source");
|
|
322
307
|
}
|
|
323
|
-
console.log(`\u2705 WASM binary loaded successfully (${wasmBinary.byteLength} bytes)`);
|
|
324
308
|
if (!isNode()) {
|
|
325
309
|
setupWasmInterceptors(wasmBinary);
|
|
326
310
|
window.Module = {
|
|
327
311
|
wasmBinary,
|
|
328
312
|
locateFile: (path) => {
|
|
329
|
-
console.log(`\u{1F50D} locateFile called for: ${path}`);
|
|
330
313
|
return path;
|
|
331
314
|
}
|
|
332
315
|
};
|
|
333
|
-
console.log(`\u{1F30D} Set global Module.wasmBinary (${wasmBinary.byteLength} bytes)`);
|
|
334
316
|
}
|
|
335
|
-
console.log("\u{1F504} Importing harfbuzzjs/hb.js (factory)");
|
|
336
317
|
const hbModule = await import("harfbuzzjs/hb.js");
|
|
337
318
|
const hbFactory = hbModule.default || hbModule;
|
|
338
|
-
console.log("\u{1F504} Calling hb factory with wasmBinary");
|
|
339
319
|
const hbInstance = await hbFactory({ wasmBinary });
|
|
340
|
-
console.log("\u{1F504} Importing harfbuzzjs/hbjs.js (wrapper)");
|
|
341
320
|
const hbjsModule = await import("harfbuzzjs/hbjs.js");
|
|
342
321
|
const hbjsWrapper = hbjsModule.default || hbjsModule;
|
|
343
|
-
console.log("\u{1F504} Wrapping hb instance");
|
|
344
322
|
const hb = hbjsWrapper(hbInstance);
|
|
345
323
|
if (!hb || typeof hb.createBuffer !== "function" || typeof hb.createFont !== "function") {
|
|
346
324
|
throw new Error("Failed to initialize HarfBuzz: unexpected export shape from 'harfbuzzjs'.");
|
|
347
325
|
}
|
|
348
326
|
hbSingleton = hb;
|
|
349
|
-
console.log("\u2705 HarfBuzz initialized successfully");
|
|
350
327
|
return hbSingleton;
|
|
351
328
|
} catch (err) {
|
|
352
329
|
console.error("Failed to initialize HarfBuzz:", err);
|
|
@@ -857,7 +834,6 @@ async function buildDrawOps(p) {
|
|
|
857
834
|
pixelRatio: p.canvas.pixelRatio,
|
|
858
835
|
clear: true,
|
|
859
836
|
bg: void 0
|
|
860
|
-
// Background will be drawn as a separate layer with proper padding/border
|
|
861
837
|
});
|
|
862
838
|
if (p.lines.length === 0) return ops;
|
|
863
839
|
const upem = Math.max(1, await p.getUnitsPerEm());
|
|
@@ -985,7 +961,12 @@ async function buildDrawOps(p) {
|
|
|
985
961
|
}
|
|
986
962
|
}
|
|
987
963
|
if (gMinX !== Infinity) {
|
|
988
|
-
const gbox = {
|
|
964
|
+
const gbox = {
|
|
965
|
+
x: gMinX,
|
|
966
|
+
y: gMinY,
|
|
967
|
+
w: Math.max(1, gMaxX - gMinX),
|
|
968
|
+
h: Math.max(1, gMaxY - gMinY)
|
|
969
|
+
};
|
|
989
970
|
for (const op of textOps) {
|
|
990
971
|
if (op.op === "FillPath" && !op.isShadow) {
|
|
991
972
|
op.gradientBBox = gbox;
|
|
@@ -993,14 +974,16 @@ async function buildDrawOps(p) {
|
|
|
993
974
|
}
|
|
994
975
|
}
|
|
995
976
|
if (p.background || p.border) {
|
|
996
|
-
const
|
|
997
|
-
const
|
|
998
|
-
const bgWidth = p.canvas.width;
|
|
999
|
-
const bgHeight = p.canvas.height;
|
|
977
|
+
const contentWidth = p.contentRect?.width ?? p.canvas.width;
|
|
978
|
+
const contentHeight = p.contentRect?.height ?? p.canvas.height;
|
|
1000
979
|
const borderWidth2 = p.border?.width ?? 0;
|
|
1001
980
|
const borderRadius = p.border?.radius ?? 0;
|
|
1002
981
|
const halfBorder = borderWidth2 / 2;
|
|
1003
|
-
const
|
|
982
|
+
const canvasCenterX = p.canvas.width / 2;
|
|
983
|
+
const canvasCenterY = p.canvas.height / 2;
|
|
984
|
+
const bgX = canvasCenterX - contentWidth / 2;
|
|
985
|
+
const bgY = canvasCenterY - contentHeight / 2;
|
|
986
|
+
const maxRadius = Math.min(contentWidth - borderWidth2, contentHeight - borderWidth2) / 2;
|
|
1004
987
|
const outerRadius = Math.min(borderRadius, maxRadius);
|
|
1005
988
|
const innerRadius = Math.max(0, outerRadius - halfBorder);
|
|
1006
989
|
if (p.background?.color) {
|
|
@@ -1008,8 +991,8 @@ async function buildDrawOps(p) {
|
|
|
1008
991
|
op: "Rectangle",
|
|
1009
992
|
x: bgX + borderWidth2,
|
|
1010
993
|
y: bgY + borderWidth2,
|
|
1011
|
-
width:
|
|
1012
|
-
height:
|
|
994
|
+
width: contentWidth - borderWidth2 * 2,
|
|
995
|
+
height: contentHeight - borderWidth2 * 2,
|
|
1013
996
|
fill: { kind: "solid", color: p.background.color, opacity: p.background.opacity },
|
|
1014
997
|
borderRadius: innerRadius
|
|
1015
998
|
});
|
|
@@ -1019,8 +1002,8 @@ async function buildDrawOps(p) {
|
|
|
1019
1002
|
op: "RectangleStroke",
|
|
1020
1003
|
x: bgX + halfBorder,
|
|
1021
1004
|
y: bgY + halfBorder,
|
|
1022
|
-
width:
|
|
1023
|
-
height:
|
|
1005
|
+
width: contentWidth - borderWidth2,
|
|
1006
|
+
height: contentHeight - borderWidth2,
|
|
1024
1007
|
stroke: {
|
|
1025
1008
|
width: p.border.width,
|
|
1026
1009
|
color: p.border.color,
|
|
@@ -2455,9 +2438,15 @@ async function createTextEngine(opts = {}) {
|
|
|
2455
2438
|
emojiAvailable = true;
|
|
2456
2439
|
} catch {
|
|
2457
2440
|
}
|
|
2441
|
+
const padding2 = asset.padding ? typeof asset.padding === "number" ? {
|
|
2442
|
+
top: asset.padding,
|
|
2443
|
+
right: asset.padding,
|
|
2444
|
+
bottom: asset.padding,
|
|
2445
|
+
left: asset.padding
|
|
2446
|
+
} : asset.padding : { top: 0, right: 0, bottom: 0, left: 0 };
|
|
2458
2447
|
lines = await layout.layout({
|
|
2459
2448
|
text: asset.text,
|
|
2460
|
-
width: asset.width ?? width,
|
|
2449
|
+
width: (asset.width ?? width) - padding2.left - padding2.right,
|
|
2461
2450
|
letterSpacing: asset.style?.letterSpacing ?? 0,
|
|
2462
2451
|
fontSize: main.size,
|
|
2463
2452
|
lineHeight: asset.style?.lineHeight ?? 1.2,
|
|
@@ -2470,23 +2459,31 @@ async function createTextEngine(opts = {}) {
|
|
|
2470
2459
|
`Failed to layout text: ${err instanceof Error ? err.message : String(err)}`
|
|
2471
2460
|
);
|
|
2472
2461
|
}
|
|
2473
|
-
const padding = asset.padding ? typeof asset.padding === "number" ? {
|
|
2462
|
+
const padding = asset.padding ? typeof asset.padding === "number" ? {
|
|
2463
|
+
top: asset.padding,
|
|
2464
|
+
right: asset.padding,
|
|
2465
|
+
bottom: asset.padding,
|
|
2466
|
+
left: asset.padding
|
|
2467
|
+
} : asset.padding : { top: 0, right: 0, bottom: 0, left: 0 };
|
|
2468
|
+
const borderWidth = asset.border?.width ?? 0;
|
|
2469
|
+
const canvasW = (asset.width ?? width) + borderWidth * 2;
|
|
2470
|
+
const canvasH = (asset.height ?? height) + borderWidth * 2;
|
|
2471
|
+
const canvasPR = pixelRatio;
|
|
2474
2472
|
const textRect = {
|
|
2475
2473
|
x: 0,
|
|
2476
2474
|
y: 0,
|
|
2477
|
-
width: asset.width ?? width,
|
|
2478
|
-
height: asset.height ?? height
|
|
2475
|
+
width: (asset.width ?? width) - padding.left - padding.right,
|
|
2476
|
+
height: (asset.height ?? height) - padding.top - padding.bottom
|
|
2479
2477
|
};
|
|
2480
|
-
const
|
|
2481
|
-
const
|
|
2482
|
-
const canvasH = (asset.height ?? height) + padding.top + padding.bottom + borderWidth * 2;
|
|
2483
|
-
const canvasPR = pixelRatio;
|
|
2478
|
+
const contentW = canvasW;
|
|
2479
|
+
const contentH = canvasH;
|
|
2484
2480
|
let ops0;
|
|
2485
2481
|
try {
|
|
2486
2482
|
ops0 = await buildDrawOps({
|
|
2487
2483
|
canvas: { width: canvasW, height: canvasH, pixelRatio: canvasPR },
|
|
2488
2484
|
textRect,
|
|
2489
2485
|
lines,
|
|
2486
|
+
contentRect: { width: contentW, height: contentH },
|
|
2490
2487
|
font: {
|
|
2491
2488
|
family: main.family,
|
|
2492
2489
|
size: main.size,
|
|
@@ -2565,10 +2562,9 @@ async function createTextEngine(opts = {}) {
|
|
|
2565
2562
|
console.log(
|
|
2566
2563
|
`\u{1F3A8} Video settings: Animation=${hasAnimation}, Background=${hasBackground}, BorderRadius=${hasBorderRadius}, Alpha=${needsAlpha}`
|
|
2567
2564
|
);
|
|
2568
|
-
const padding = asset.padding ? typeof asset.padding === "number" ? { left: asset.padding, right: asset.padding, top: asset.padding, bottom: asset.padding } : asset.padding : { left: 0, right: 0, top: 0, bottom: 0 };
|
|
2569
2565
|
const borderWidth = asset.border?.width ?? 0;
|
|
2570
|
-
const canvasWidth = (asset.width ?? width) +
|
|
2571
|
-
const canvasHeight = (asset.height ?? height) +
|
|
2566
|
+
const canvasWidth = (asset.width ?? width) + borderWidth * 2;
|
|
2567
|
+
const canvasHeight = (asset.height ?? height) + borderWidth * 2;
|
|
2572
2568
|
const finalOptions = {
|
|
2573
2569
|
width: canvasWidth,
|
|
2574
2570
|
height: canvasHeight,
|
package/dist/entry.web.js
CHANGED
|
@@ -161,13 +161,11 @@ function bufferToArrayBuffer(buffer) {
|
|
|
161
161
|
var DEFAULT_WASM_URL = "https://shotstack-ingest-api-dev-sources.s3.ap-southeast-2.amazonaws.com/euo5r93oyr/zzz01k9h-yycyx-2x2y6-qx9bj-7n567b/source.wasm";
|
|
162
162
|
async function fetchWasmFromUrl(url) {
|
|
163
163
|
try {
|
|
164
|
-
console.log(`\u{1F310} Fetching WASM from URL: ${url}`);
|
|
165
164
|
const response = await fetch(url);
|
|
166
165
|
if (response.ok) {
|
|
167
166
|
const arrayBuffer = await response.arrayBuffer();
|
|
168
167
|
const bytes = new Uint8Array(arrayBuffer);
|
|
169
168
|
if (bytes.length >= 4 && bytes[0] === 0 && bytes[1] === 97 && bytes[2] === 115 && bytes[3] === 109) {
|
|
170
|
-
console.log(`\u2705 Fetched WASM from URL (${bytes.length} bytes)`);
|
|
171
169
|
return arrayBuffer;
|
|
172
170
|
} else {
|
|
173
171
|
console.error(`\u274C Invalid WASM magic number from URL: ${url}`);
|
|
@@ -215,21 +213,17 @@ async function loadWasmNode() {
|
|
|
215
213
|
"/var/task/node_modules/harfbuzzjs/hb.wasm",
|
|
216
214
|
"/var/task/node_modules/@shotstack/shotstack-canvas/assets/wasm/hb.wasm"
|
|
217
215
|
);
|
|
218
|
-
console.log(`\u{1F50D} Searching for WASM in ${candidates.length} local paths...`);
|
|
219
216
|
for (const candidate of candidates) {
|
|
220
217
|
try {
|
|
221
218
|
const buffer = await readFile(candidate);
|
|
222
|
-
console.log(`\u2705 Found WASM at: ${candidate}`);
|
|
223
219
|
return bufferToArrayBuffer(buffer);
|
|
224
220
|
} catch {
|
|
225
221
|
continue;
|
|
226
222
|
}
|
|
227
223
|
}
|
|
228
|
-
console.log("\u{1F4C2} Local WASM not found, fetching from URL...");
|
|
229
224
|
return await fetchWasmFromUrl(DEFAULT_WASM_URL);
|
|
230
225
|
} catch (err) {
|
|
231
226
|
console.error("Error in loadWasmNode:", err);
|
|
232
|
-
console.log("\u26A0\uFE0F Error during local search, falling back to URL...");
|
|
233
227
|
return await fetchWasmFromUrl(DEFAULT_WASM_URL);
|
|
234
228
|
}
|
|
235
229
|
}
|
|
@@ -237,13 +231,11 @@ async function loadWasmWeb(wasmBaseURL) {
|
|
|
237
231
|
try {
|
|
238
232
|
if (wasmBaseURL) {
|
|
239
233
|
const url = wasmBaseURL.endsWith(".wasm") ? wasmBaseURL : wasmBaseURL.endsWith("/") ? `${wasmBaseURL}hb.wasm` : `${wasmBaseURL}/hb.wasm`;
|
|
240
|
-
console.log(`Fetching WASM from: ${url}`);
|
|
241
234
|
const response = await fetch(url);
|
|
242
235
|
if (response.ok) {
|
|
243
236
|
const arrayBuffer = await response.arrayBuffer();
|
|
244
237
|
const bytes = new Uint8Array(arrayBuffer);
|
|
245
238
|
if (bytes.length >= 4 && bytes[0] === 0 && bytes[1] === 97 && bytes[2] === 115 && bytes[3] === 109) {
|
|
246
|
-
console.log(`\u2705 Valid WASM binary loaded (${bytes.length} bytes)`);
|
|
247
239
|
return arrayBuffer;
|
|
248
240
|
}
|
|
249
241
|
}
|
|
@@ -259,7 +251,6 @@ function setupWasmInterceptors(wasmBinary) {
|
|
|
259
251
|
window.fetch = function(input, init) {
|
|
260
252
|
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
261
253
|
if (url.includes("hb.wasm") || url.endsWith(".wasm") && !url.includes("source.wasm")) {
|
|
262
|
-
console.log(`\u{1F504} Intercepted fetch for: ${url}`);
|
|
263
254
|
return Promise.resolve(
|
|
264
255
|
new Response(wasmBinary.slice(0), {
|
|
265
256
|
status: 200,
|
|
@@ -275,13 +266,9 @@ function setupWasmInterceptors(wasmBinary) {
|
|
|
275
266
|
};
|
|
276
267
|
const originalInstantiate = WebAssembly.instantiate;
|
|
277
268
|
WebAssembly.instantiate = async function(bufferSourceOrModule, importObject) {
|
|
278
|
-
console.log(
|
|
279
|
-
`\u{1F504} WebAssembly.instantiate called, type: ${bufferSourceOrModule instanceof WebAssembly.Module ? "Module" : "BufferSource"}`
|
|
280
|
-
);
|
|
281
269
|
if (bufferSourceOrModule instanceof WebAssembly.Module) {
|
|
282
270
|
return originalInstantiate.call(WebAssembly, bufferSourceOrModule, importObject);
|
|
283
271
|
}
|
|
284
|
-
console.log(`\u{1F504} Intercepted WebAssembly.instantiate, using pre-loaded WASM binary`);
|
|
285
272
|
const module = await WebAssembly.compile(wasmBinary);
|
|
286
273
|
const instance = await originalInstantiate.call(
|
|
287
274
|
WebAssembly,
|
|
@@ -297,14 +284,12 @@ function setupWasmInterceptors(wasmBinary) {
|
|
|
297
284
|
const response = await source;
|
|
298
285
|
const url = response.url || "";
|
|
299
286
|
if (url.includes("hb.wasm") || url.endsWith(".wasm") && !url.includes("source.wasm")) {
|
|
300
|
-
console.log(`\u{1F504} Intercepted instantiateStreaming for: ${url}`);
|
|
301
287
|
const module = await WebAssembly.compile(wasmBinary);
|
|
302
288
|
const instance = await WebAssembly.instantiate(module, importObject);
|
|
303
289
|
return { module, instance };
|
|
304
290
|
}
|
|
305
291
|
return originalInstantiateStreaming.call(WebAssembly, response, importObject);
|
|
306
292
|
} catch (err) {
|
|
307
|
-
console.log("\u{1F504} instantiateStreaming failed, using pre-loaded binary");
|
|
308
293
|
const module = await WebAssembly.compile(wasmBinary);
|
|
309
294
|
const instance = await WebAssembly.instantiate(module, importObject);
|
|
310
295
|
return { module, instance };
|
|
@@ -324,33 +309,25 @@ async function initHB(wasmBaseURL) {
|
|
|
324
309
|
if (!wasmBinary) {
|
|
325
310
|
throw new Error("Failed to load WASM binary from any source");
|
|
326
311
|
}
|
|
327
|
-
console.log(`\u2705 WASM binary loaded successfully (${wasmBinary.byteLength} bytes)`);
|
|
328
312
|
if (!isNode()) {
|
|
329
313
|
setupWasmInterceptors(wasmBinary);
|
|
330
314
|
window.Module = {
|
|
331
315
|
wasmBinary,
|
|
332
316
|
locateFile: (path) => {
|
|
333
|
-
console.log(`\u{1F50D} locateFile called for: ${path}`);
|
|
334
317
|
return path;
|
|
335
318
|
}
|
|
336
319
|
};
|
|
337
|
-
console.log(`\u{1F30D} Set global Module.wasmBinary (${wasmBinary.byteLength} bytes)`);
|
|
338
320
|
}
|
|
339
|
-
console.log("\u{1F504} Importing harfbuzzjs/hb.js (factory)");
|
|
340
321
|
const hbModule = await import("./hb-ODWKSLMB.js");
|
|
341
322
|
const hbFactory = hbModule.default || hbModule;
|
|
342
|
-
console.log("\u{1F504} Calling hb factory with wasmBinary");
|
|
343
323
|
const hbInstance = await hbFactory({ wasmBinary });
|
|
344
|
-
console.log("\u{1F504} Importing harfbuzzjs/hbjs.js (wrapper)");
|
|
345
324
|
const hbjsModule = await import("./hbjs-HHU2TAW7.js");
|
|
346
325
|
const hbjsWrapper = hbjsModule.default || hbjsModule;
|
|
347
|
-
console.log("\u{1F504} Wrapping hb instance");
|
|
348
326
|
const hb = hbjsWrapper(hbInstance);
|
|
349
327
|
if (!hb || typeof hb.createBuffer !== "function" || typeof hb.createFont !== "function") {
|
|
350
328
|
throw new Error("Failed to initialize HarfBuzz: unexpected export shape from 'harfbuzzjs'.");
|
|
351
329
|
}
|
|
352
330
|
hbSingleton = hb;
|
|
353
|
-
console.log("\u2705 HarfBuzz initialized successfully");
|
|
354
331
|
return hbSingleton;
|
|
355
332
|
} catch (err) {
|
|
356
333
|
console.error("Failed to initialize HarfBuzz:", err);
|
|
@@ -862,7 +839,6 @@ async function buildDrawOps(p) {
|
|
|
862
839
|
pixelRatio: p.canvas.pixelRatio,
|
|
863
840
|
clear: true,
|
|
864
841
|
bg: void 0
|
|
865
|
-
// Background will be drawn as a separate layer with proper padding/border
|
|
866
842
|
});
|
|
867
843
|
if (p.lines.length === 0) return ops;
|
|
868
844
|
const upem = Math.max(1, await p.getUnitsPerEm());
|
|
@@ -990,7 +966,12 @@ async function buildDrawOps(p) {
|
|
|
990
966
|
}
|
|
991
967
|
}
|
|
992
968
|
if (gMinX !== Infinity) {
|
|
993
|
-
const gbox = {
|
|
969
|
+
const gbox = {
|
|
970
|
+
x: gMinX,
|
|
971
|
+
y: gMinY,
|
|
972
|
+
w: Math.max(1, gMaxX - gMinX),
|
|
973
|
+
h: Math.max(1, gMaxY - gMinY)
|
|
974
|
+
};
|
|
994
975
|
for (const op of textOps) {
|
|
995
976
|
if (op.op === "FillPath" && !op.isShadow) {
|
|
996
977
|
op.gradientBBox = gbox;
|
|
@@ -998,14 +979,16 @@ async function buildDrawOps(p) {
|
|
|
998
979
|
}
|
|
999
980
|
}
|
|
1000
981
|
if (p.background || p.border) {
|
|
1001
|
-
const
|
|
1002
|
-
const
|
|
1003
|
-
const bgWidth = p.canvas.width;
|
|
1004
|
-
const bgHeight = p.canvas.height;
|
|
982
|
+
const contentWidth = p.contentRect?.width ?? p.canvas.width;
|
|
983
|
+
const contentHeight = p.contentRect?.height ?? p.canvas.height;
|
|
1005
984
|
const borderWidth2 = p.border?.width ?? 0;
|
|
1006
985
|
const borderRadius = p.border?.radius ?? 0;
|
|
1007
986
|
const halfBorder = borderWidth2 / 2;
|
|
1008
|
-
const
|
|
987
|
+
const canvasCenterX = p.canvas.width / 2;
|
|
988
|
+
const canvasCenterY = p.canvas.height / 2;
|
|
989
|
+
const bgX = canvasCenterX - contentWidth / 2;
|
|
990
|
+
const bgY = canvasCenterY - contentHeight / 2;
|
|
991
|
+
const maxRadius = Math.min(contentWidth - borderWidth2, contentHeight - borderWidth2) / 2;
|
|
1009
992
|
const outerRadius = Math.min(borderRadius, maxRadius);
|
|
1010
993
|
const innerRadius = Math.max(0, outerRadius - halfBorder);
|
|
1011
994
|
if (p.background?.color) {
|
|
@@ -1013,8 +996,8 @@ async function buildDrawOps(p) {
|
|
|
1013
996
|
op: "Rectangle",
|
|
1014
997
|
x: bgX + borderWidth2,
|
|
1015
998
|
y: bgY + borderWidth2,
|
|
1016
|
-
width:
|
|
1017
|
-
height:
|
|
999
|
+
width: contentWidth - borderWidth2 * 2,
|
|
1000
|
+
height: contentHeight - borderWidth2 * 2,
|
|
1018
1001
|
fill: { kind: "solid", color: p.background.color, opacity: p.background.opacity },
|
|
1019
1002
|
borderRadius: innerRadius
|
|
1020
1003
|
});
|
|
@@ -1024,8 +1007,8 @@ async function buildDrawOps(p) {
|
|
|
1024
1007
|
op: "RectangleStroke",
|
|
1025
1008
|
x: bgX + halfBorder,
|
|
1026
1009
|
y: bgY + halfBorder,
|
|
1027
|
-
width:
|
|
1028
|
-
height:
|
|
1010
|
+
width: contentWidth - borderWidth2,
|
|
1011
|
+
height: contentHeight - borderWidth2,
|
|
1029
1012
|
stroke: {
|
|
1030
1013
|
width: p.border.width,
|
|
1031
1014
|
color: p.border.color,
|
|
@@ -2166,9 +2149,10 @@ async function createTextEngine(opts = {}) {
|
|
|
2166
2149
|
emojiAvailable = true;
|
|
2167
2150
|
} catch {
|
|
2168
2151
|
}
|
|
2152
|
+
const padding2 = asset.padding ? typeof asset.padding === "number" ? { top: asset.padding, right: asset.padding, bottom: asset.padding, left: asset.padding } : asset.padding : { top: 0, right: 0, bottom: 0, left: 0 };
|
|
2169
2153
|
lines = await layout.layout({
|
|
2170
2154
|
text: asset.text,
|
|
2171
|
-
width: asset.width ?? width,
|
|
2155
|
+
width: (asset.width ?? width) - padding2.left - padding2.right,
|
|
2172
2156
|
letterSpacing: asset.style?.letterSpacing ?? 0,
|
|
2173
2157
|
fontSize: main.size,
|
|
2174
2158
|
lineHeight: asset.style?.lineHeight ?? 1.2,
|
|
@@ -2182,22 +2166,25 @@ async function createTextEngine(opts = {}) {
|
|
|
2182
2166
|
);
|
|
2183
2167
|
}
|
|
2184
2168
|
const padding = asset.padding ? typeof asset.padding === "number" ? { top: asset.padding, right: asset.padding, bottom: asset.padding, left: asset.padding } : asset.padding : { top: 0, right: 0, bottom: 0, left: 0 };
|
|
2169
|
+
const borderWidth = asset.border?.width ?? 0;
|
|
2170
|
+
const canvasW = (asset.width ?? width) + borderWidth * 2;
|
|
2171
|
+
const canvasH = (asset.height ?? height) + borderWidth * 2;
|
|
2172
|
+
const canvasPR = pixelRatio;
|
|
2185
2173
|
const textRect = {
|
|
2186
2174
|
x: 0,
|
|
2187
2175
|
y: 0,
|
|
2188
|
-
width: asset.width ?? width,
|
|
2189
|
-
height: asset.height ?? height
|
|
2176
|
+
width: (asset.width ?? width) - padding.left - padding.right,
|
|
2177
|
+
height: (asset.height ?? height) - padding.top - padding.bottom
|
|
2190
2178
|
};
|
|
2191
|
-
const
|
|
2192
|
-
const
|
|
2193
|
-
const canvasH = (asset.height ?? height) + padding.top + padding.bottom + borderWidth * 2;
|
|
2194
|
-
const canvasPR = pixelRatio;
|
|
2179
|
+
const contentW = canvasW;
|
|
2180
|
+
const contentH = canvasH;
|
|
2195
2181
|
let ops0;
|
|
2196
2182
|
try {
|
|
2197
2183
|
ops0 = await buildDrawOps({
|
|
2198
2184
|
canvas: { width: canvasW, height: canvasH, pixelRatio: canvasPR },
|
|
2199
2185
|
textRect,
|
|
2200
2186
|
lines,
|
|
2187
|
+
contentRect: { width: contentW, height: contentH },
|
|
2201
2188
|
font: {
|
|
2202
2189
|
family: main.family,
|
|
2203
2190
|
size: main.size,
|
package/package.json
CHANGED