asciify-engine 1.0.70 → 1.0.71
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/index.cjs +66 -69
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +66 -69
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1167,23 +1167,14 @@ function getSourceDims(el) {
|
|
|
1167
1167
|
if (el instanceof HTMLImageElement) return { w: el.naturalWidth || el.width, h: el.naturalHeight || el.height };
|
|
1168
1168
|
return { w: el.width, h: el.height };
|
|
1169
1169
|
}
|
|
1170
|
-
function
|
|
1171
|
-
if (srcW <= displayW && srcH <= displayH) return null;
|
|
1170
|
+
function computeRenderDims(srcW, srcH) {
|
|
1172
1171
|
const MAX = 2048;
|
|
1173
1172
|
const scale = Math.min(1, MAX / Math.max(srcW, srcH));
|
|
1174
|
-
|
|
1175
|
-
const offH = Math.round(srcH * scale);
|
|
1176
|
-
if (offW <= displayW && offH <= displayH) return null;
|
|
1177
|
-
const offCanvas = document.createElement("canvas");
|
|
1178
|
-
offCanvas.width = offW;
|
|
1179
|
-
offCanvas.height = offH;
|
|
1180
|
-
const offCtx = offCanvas.getContext("2d");
|
|
1181
|
-
if (!offCtx) return null;
|
|
1182
|
-
return { offCanvas, offCtx, offW, offH };
|
|
1173
|
+
return { renderW: Math.round(srcW * scale), renderH: Math.round(srcH * scale) };
|
|
1183
1174
|
}
|
|
1184
1175
|
function sizeCanvasToContainer(canvas, container, aspect, srcW, srcH) {
|
|
1185
1176
|
const { width, height } = container.getBoundingClientRect();
|
|
1186
|
-
if (!width || !height) return;
|
|
1177
|
+
if (!width || !height) return { renderW: 0, renderH: 0, dpr: 1 };
|
|
1187
1178
|
let cssW = width, cssH = cssW / aspect;
|
|
1188
1179
|
if (cssH > height) {
|
|
1189
1180
|
cssH = height;
|
|
@@ -1191,21 +1182,21 @@ function sizeCanvasToContainer(canvas, container, aspect, srcW, srcH) {
|
|
|
1191
1182
|
}
|
|
1192
1183
|
cssW = Math.round(cssW);
|
|
1193
1184
|
cssH = Math.round(cssH);
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
const scale = Math.min(1, MAX_BUF / Math.max(srcW, srcH));
|
|
1198
|
-
bufW = Math.round(srcW * scale);
|
|
1199
|
-
bufH = Math.round(srcH * scale);
|
|
1185
|
+
let renderW, renderH;
|
|
1186
|
+
if (srcW && srcH) {
|
|
1187
|
+
({ renderW, renderH } = computeRenderDims(srcW, srcH));
|
|
1200
1188
|
} else {
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1189
|
+
renderW = cssW;
|
|
1190
|
+
renderH = cssH;
|
|
1191
|
+
}
|
|
1192
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
1193
|
+
const MAX_PX = 8e6;
|
|
1194
|
+
const cappedDpr = renderW * dpr * renderH * dpr > MAX_PX ? Math.sqrt(MAX_PX / (renderW * renderH)) : dpr;
|
|
1195
|
+
canvas.width = Math.round(renderW * cappedDpr);
|
|
1196
|
+
canvas.height = Math.round(renderH * cappedDpr);
|
|
1207
1197
|
canvas.style.width = cssW + "px";
|
|
1208
1198
|
canvas.style.height = cssH + "px";
|
|
1199
|
+
return { renderW, renderH, dpr: cappedDpr };
|
|
1209
1200
|
}
|
|
1210
1201
|
async function asciify(source, canvas, { fontSize, artStyle = "classic", options = {} } = {}) {
|
|
1211
1202
|
let el;
|
|
@@ -1233,16 +1224,19 @@ async function asciify(source, canvas, { fontSize, artStyle = "classic", options
|
|
|
1233
1224
|
const ctx = canvas.getContext("2d");
|
|
1234
1225
|
if (!ctx) throw new Error("Could not get 2d context from canvas");
|
|
1235
1226
|
const { w: srcW, h: srcH } = getSourceDims(el);
|
|
1236
|
-
const
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1227
|
+
const { renderW, renderH } = computeRenderDims(srcW, srcH);
|
|
1228
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
1229
|
+
const MAX_PX = 8e6;
|
|
1230
|
+
const cappedDpr = renderW * dpr * renderH * dpr > MAX_PX ? Math.sqrt(MAX_PX / (renderW * renderH)) : dpr;
|
|
1231
|
+
if (canvas.width < renderW || canvas.height < renderH) {
|
|
1232
|
+
canvas.width = Math.round(renderW * cappedDpr);
|
|
1233
|
+
canvas.height = Math.round(renderH * cappedDpr);
|
|
1234
|
+
}
|
|
1235
|
+
const { frame } = imageToAsciiFrame(el, merged, renderW, renderH);
|
|
1236
|
+
ctx.save();
|
|
1237
|
+
ctx.setTransform(cappedDpr, 0, 0, cappedDpr, 0, 0);
|
|
1238
|
+
renderFrameToCanvas(ctx, frame, merged, renderW, renderH);
|
|
1239
|
+
ctx.restore();
|
|
1246
1240
|
}
|
|
1247
1241
|
async function asciifyGif(source, canvas, { fontSize, artStyle = "classic", options = {} } = {}) {
|
|
1248
1242
|
const buffer = typeof source === "string" ? await fetch(source).then((r) => r.arrayBuffer()) : source;
|
|
@@ -1295,24 +1289,26 @@ async function asciifyVideo(source, canvas, { fontSize, artStyle = "classic", op
|
|
|
1295
1289
|
video2 = source;
|
|
1296
1290
|
}
|
|
1297
1291
|
if (container) sizeCanvasToContainer(canvas, container, video2.videoWidth / video2.videoHeight, video2.videoWidth, video2.videoHeight);
|
|
1298
|
-
const
|
|
1299
|
-
const
|
|
1300
|
-
const
|
|
1292
|
+
const { renderW: renderW2, renderH: renderH2 } = computeRenderDims(video2.videoWidth, video2.videoHeight);
|
|
1293
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
1294
|
+
const MAX_PX = 8e6;
|
|
1295
|
+
const cappedDpr = renderW2 * dpr * renderH2 * dpr > MAX_PX ? Math.sqrt(MAX_PX / (renderW2 * renderH2)) : dpr;
|
|
1296
|
+
if (canvas.width < Math.round(renderW2 * cappedDpr)) {
|
|
1297
|
+
canvas.width = Math.round(renderW2 * cappedDpr);
|
|
1298
|
+
canvas.height = Math.round(renderH2 * cappedDpr);
|
|
1299
|
+
}
|
|
1301
1300
|
const maxDur = trimEnd !== void 0 ? trimEnd - trimStart : 10;
|
|
1302
|
-
const { frames, fps } = await videoToAsciiFrames(video2, merged,
|
|
1301
|
+
const { frames, fps } = await videoToAsciiFrames(video2, merged, renderW2, renderH2, void 0, maxDur, void 0, trimStart);
|
|
1303
1302
|
let cancelled2 = false, animId2, i = 0, last = performance.now();
|
|
1304
1303
|
let firstFrame2 = true;
|
|
1305
1304
|
const interval = 1e3 / fps;
|
|
1306
1305
|
const tick2 = (now) => {
|
|
1307
1306
|
if (cancelled2) return;
|
|
1308
1307
|
if (now - last >= interval) {
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
} else {
|
|
1314
|
-
renderFrameToCanvas(ctx, frames[i], merged, canvas.width, canvas.height);
|
|
1315
|
-
}
|
|
1308
|
+
ctx.save();
|
|
1309
|
+
ctx.setTransform(cappedDpr, 0, 0, cappedDpr, 0, 0);
|
|
1310
|
+
renderFrameToCanvas(ctx, frames[i], merged, renderW2, renderH2);
|
|
1311
|
+
ctx.restore();
|
|
1316
1312
|
i = (i + 1) % frames.length;
|
|
1317
1313
|
last = now;
|
|
1318
1314
|
if (firstFrame2) {
|
|
@@ -1383,14 +1379,29 @@ async function asciifyVideo(source, canvas, { fontSize, artStyle = "classic", op
|
|
|
1383
1379
|
video.addEventListener("timeupdate", timeupdateHandler);
|
|
1384
1380
|
}
|
|
1385
1381
|
let ro = null;
|
|
1382
|
+
const { renderW, renderH } = computeRenderDims(video.videoWidth, video.videoHeight);
|
|
1386
1383
|
if (container) {
|
|
1387
1384
|
const aspect = video.videoWidth / video.videoHeight;
|
|
1388
1385
|
const vw = video.videoWidth, vh = video.videoHeight;
|
|
1389
|
-
sizeCanvasToContainer(canvas, container, aspect, vw, vh);
|
|
1390
|
-
|
|
1386
|
+
const sizing = sizeCanvasToContainer(canvas, container, aspect, vw, vh);
|
|
1387
|
+
const sCtx = canvas.getContext("2d");
|
|
1388
|
+
if (sCtx) sCtx.setTransform(sizing.dpr, 0, 0, sizing.dpr, 0, 0);
|
|
1389
|
+
ro = new ResizeObserver(() => {
|
|
1390
|
+
const s = sizeCanvasToContainer(canvas, container, aspect, vw, vh);
|
|
1391
|
+
const rCtx = canvas.getContext("2d");
|
|
1392
|
+
if (rCtx) rCtx.setTransform(s.dpr, 0, 0, s.dpr, 0, 0);
|
|
1393
|
+
});
|
|
1391
1394
|
ro.observe(container);
|
|
1395
|
+
} else {
|
|
1396
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
1397
|
+
const MAX_PX = 8e6;
|
|
1398
|
+
const cappedDpr = renderW * dpr * renderH * dpr > MAX_PX ? Math.sqrt(MAX_PX / (renderW * renderH)) : dpr;
|
|
1399
|
+
if (canvas.width < Math.round(renderW * cappedDpr)) {
|
|
1400
|
+
canvas.width = Math.round(renderW * cappedDpr);
|
|
1401
|
+
canvas.height = Math.round(renderH * cappedDpr);
|
|
1402
|
+
}
|
|
1403
|
+
ctx.setTransform(cappedDpr, 0, 0, cappedDpr, 0, 0);
|
|
1392
1404
|
}
|
|
1393
|
-
const hires = makeHiResCanvas(video.videoWidth, video.videoHeight, canvas.width, canvas.height);
|
|
1394
1405
|
let cancelled = false;
|
|
1395
1406
|
let animId;
|
|
1396
1407
|
let firstFrame = true;
|
|
@@ -1400,28 +1411,14 @@ async function asciifyVideo(source, canvas, { fontSize, artStyle = "classic", op
|
|
|
1400
1411
|
if (video.readyState < 2 || canvas.width === 0 || canvas.height === 0) return;
|
|
1401
1412
|
if (trimStart > 0 && video.currentTime < trimStart) return;
|
|
1402
1413
|
if (trimEnd !== void 0 && video.currentTime >= trimEnd) return;
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
if (firstFrame) {
|
|
1410
|
-
firstFrame = false;
|
|
1411
|
-
onReady?.(video);
|
|
1412
|
-
}
|
|
1413
|
-
onFrame?.();
|
|
1414
|
-
}
|
|
1415
|
-
} else {
|
|
1416
|
-
const { frame } = imageToAsciiFrame(video, merged, canvas.width, canvas.height);
|
|
1417
|
-
if (frame.length > 0) {
|
|
1418
|
-
renderFrameToCanvas(ctx, frame, merged, canvas.width, canvas.height, 0, null);
|
|
1419
|
-
if (firstFrame) {
|
|
1420
|
-
firstFrame = false;
|
|
1421
|
-
onReady?.(video);
|
|
1422
|
-
}
|
|
1423
|
-
onFrame?.();
|
|
1414
|
+
const { frame } = imageToAsciiFrame(video, merged, renderW, renderH);
|
|
1415
|
+
if (frame.length > 0) {
|
|
1416
|
+
renderFrameToCanvas(ctx, frame, merged, renderW, renderH, 0, null);
|
|
1417
|
+
if (firstFrame) {
|
|
1418
|
+
firstFrame = false;
|
|
1419
|
+
onReady?.(video);
|
|
1424
1420
|
}
|
|
1421
|
+
onFrame?.();
|
|
1425
1422
|
}
|
|
1426
1423
|
};
|
|
1427
1424
|
animId = requestAnimationFrame(tick);
|