asciify-engine 1.0.69 → 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 +70 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +70 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1162,9 +1162,19 @@ function renderFrameToCanvas(ctx, frame, options, canvasWidth, canvasHeight, tim
|
|
|
1162
1162
|
}
|
|
1163
1163
|
|
|
1164
1164
|
// src/core/simple-api.ts
|
|
1165
|
+
function getSourceDims(el) {
|
|
1166
|
+
if (el instanceof HTMLVideoElement) return { w: el.videoWidth, h: el.videoHeight };
|
|
1167
|
+
if (el instanceof HTMLImageElement) return { w: el.naturalWidth || el.width, h: el.naturalHeight || el.height };
|
|
1168
|
+
return { w: el.width, h: el.height };
|
|
1169
|
+
}
|
|
1170
|
+
function computeRenderDims(srcW, srcH) {
|
|
1171
|
+
const MAX = 2048;
|
|
1172
|
+
const scale = Math.min(1, MAX / Math.max(srcW, srcH));
|
|
1173
|
+
return { renderW: Math.round(srcW * scale), renderH: Math.round(srcH * scale) };
|
|
1174
|
+
}
|
|
1165
1175
|
function sizeCanvasToContainer(canvas, container, aspect, srcW, srcH) {
|
|
1166
1176
|
const { width, height } = container.getBoundingClientRect();
|
|
1167
|
-
if (!width || !height) return;
|
|
1177
|
+
if (!width || !height) return { renderW: 0, renderH: 0, dpr: 1 };
|
|
1168
1178
|
let cssW = width, cssH = cssW / aspect;
|
|
1169
1179
|
if (cssH > height) {
|
|
1170
1180
|
cssH = height;
|
|
@@ -1172,21 +1182,21 @@ function sizeCanvasToContainer(canvas, container, aspect, srcW, srcH) {
|
|
|
1172
1182
|
}
|
|
1173
1183
|
cssW = Math.round(cssW);
|
|
1174
1184
|
cssH = Math.round(cssH);
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
const scale = Math.min(1, MAX_BUF / Math.max(srcW, srcH));
|
|
1179
|
-
bufW = Math.round(srcW * scale);
|
|
1180
|
-
bufH = Math.round(srcH * scale);
|
|
1185
|
+
let renderW, renderH;
|
|
1186
|
+
if (srcW && srcH) {
|
|
1187
|
+
({ renderW, renderH } = computeRenderDims(srcW, srcH));
|
|
1181
1188
|
} else {
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
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);
|
|
1188
1197
|
canvas.style.width = cssW + "px";
|
|
1189
1198
|
canvas.style.height = cssH + "px";
|
|
1199
|
+
return { renderW, renderH, dpr: cappedDpr };
|
|
1190
1200
|
}
|
|
1191
1201
|
async function asciify(source, canvas, { fontSize, artStyle = "classic", options = {} } = {}) {
|
|
1192
1202
|
let el;
|
|
@@ -1213,8 +1223,20 @@ async function asciify(source, canvas, { fontSize, artStyle = "classic", options
|
|
|
1213
1223
|
const merged = { ...DEFAULT_OPTIONS, ...preset, ...options, fontSize: resolvedFontSize };
|
|
1214
1224
|
const ctx = canvas.getContext("2d");
|
|
1215
1225
|
if (!ctx) throw new Error("Could not get 2d context from canvas");
|
|
1216
|
-
const {
|
|
1217
|
-
|
|
1226
|
+
const { w: srcW, h: srcH } = getSourceDims(el);
|
|
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();
|
|
1218
1240
|
}
|
|
1219
1241
|
async function asciifyGif(source, canvas, { fontSize, artStyle = "classic", options = {} } = {}) {
|
|
1220
1242
|
const buffer = typeof source === "string" ? await fetch(source).then((r) => r.arrayBuffer()) : source;
|
|
@@ -1267,15 +1289,26 @@ async function asciifyVideo(source, canvas, { fontSize, artStyle = "classic", op
|
|
|
1267
1289
|
video2 = source;
|
|
1268
1290
|
}
|
|
1269
1291
|
if (container) sizeCanvasToContainer(canvas, container, video2.videoWidth / video2.videoHeight, video2.videoWidth, video2.videoHeight);
|
|
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
|
+
}
|
|
1270
1300
|
const maxDur = trimEnd !== void 0 ? trimEnd - trimStart : 10;
|
|
1271
|
-
const { frames, fps } = await videoToAsciiFrames(video2, merged,
|
|
1301
|
+
const { frames, fps } = await videoToAsciiFrames(video2, merged, renderW2, renderH2, void 0, maxDur, void 0, trimStart);
|
|
1272
1302
|
let cancelled2 = false, animId2, i = 0, last = performance.now();
|
|
1273
1303
|
let firstFrame2 = true;
|
|
1274
1304
|
const interval = 1e3 / fps;
|
|
1275
1305
|
const tick2 = (now) => {
|
|
1276
1306
|
if (cancelled2) return;
|
|
1277
1307
|
if (now - last >= interval) {
|
|
1278
|
-
|
|
1308
|
+
ctx.save();
|
|
1309
|
+
ctx.setTransform(cappedDpr, 0, 0, cappedDpr, 0, 0);
|
|
1310
|
+
renderFrameToCanvas(ctx, frames[i], merged, renderW2, renderH2);
|
|
1311
|
+
ctx.restore();
|
|
1279
1312
|
i = (i + 1) % frames.length;
|
|
1280
1313
|
last = now;
|
|
1281
1314
|
if (firstFrame2) {
|
|
@@ -1346,12 +1379,28 @@ async function asciifyVideo(source, canvas, { fontSize, artStyle = "classic", op
|
|
|
1346
1379
|
video.addEventListener("timeupdate", timeupdateHandler);
|
|
1347
1380
|
}
|
|
1348
1381
|
let ro = null;
|
|
1382
|
+
const { renderW, renderH } = computeRenderDims(video.videoWidth, video.videoHeight);
|
|
1349
1383
|
if (container) {
|
|
1350
1384
|
const aspect = video.videoWidth / video.videoHeight;
|
|
1351
1385
|
const vw = video.videoWidth, vh = video.videoHeight;
|
|
1352
|
-
sizeCanvasToContainer(canvas, container, aspect, vw, vh);
|
|
1353
|
-
|
|
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
|
+
});
|
|
1354
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);
|
|
1355
1404
|
}
|
|
1356
1405
|
let cancelled = false;
|
|
1357
1406
|
let animId;
|
|
@@ -1362,9 +1411,9 @@ async function asciifyVideo(source, canvas, { fontSize, artStyle = "classic", op
|
|
|
1362
1411
|
if (video.readyState < 2 || canvas.width === 0 || canvas.height === 0) return;
|
|
1363
1412
|
if (trimStart > 0 && video.currentTime < trimStart) return;
|
|
1364
1413
|
if (trimEnd !== void 0 && video.currentTime >= trimEnd) return;
|
|
1365
|
-
const { frame } = imageToAsciiFrame(video, merged,
|
|
1414
|
+
const { frame } = imageToAsciiFrame(video, merged, renderW, renderH);
|
|
1366
1415
|
if (frame.length > 0) {
|
|
1367
|
-
renderFrameToCanvas(ctx, frame, merged,
|
|
1416
|
+
renderFrameToCanvas(ctx, frame, merged, renderW, renderH, 0, null);
|
|
1368
1417
|
if (firstFrame) {
|
|
1369
1418
|
firstFrame = false;
|
|
1370
1419
|
onReady?.(video);
|