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.js
CHANGED
|
@@ -1160,9 +1160,19 @@ function renderFrameToCanvas(ctx, frame, options, canvasWidth, canvasHeight, tim
|
|
|
1160
1160
|
}
|
|
1161
1161
|
|
|
1162
1162
|
// src/core/simple-api.ts
|
|
1163
|
+
function getSourceDims(el) {
|
|
1164
|
+
if (el instanceof HTMLVideoElement) return { w: el.videoWidth, h: el.videoHeight };
|
|
1165
|
+
if (el instanceof HTMLImageElement) return { w: el.naturalWidth || el.width, h: el.naturalHeight || el.height };
|
|
1166
|
+
return { w: el.width, h: el.height };
|
|
1167
|
+
}
|
|
1168
|
+
function computeRenderDims(srcW, srcH) {
|
|
1169
|
+
const MAX = 2048;
|
|
1170
|
+
const scale = Math.min(1, MAX / Math.max(srcW, srcH));
|
|
1171
|
+
return { renderW: Math.round(srcW * scale), renderH: Math.round(srcH * scale) };
|
|
1172
|
+
}
|
|
1163
1173
|
function sizeCanvasToContainer(canvas, container, aspect, srcW, srcH) {
|
|
1164
1174
|
const { width, height } = container.getBoundingClientRect();
|
|
1165
|
-
if (!width || !height) return;
|
|
1175
|
+
if (!width || !height) return { renderW: 0, renderH: 0, dpr: 1 };
|
|
1166
1176
|
let cssW = width, cssH = cssW / aspect;
|
|
1167
1177
|
if (cssH > height) {
|
|
1168
1178
|
cssH = height;
|
|
@@ -1170,21 +1180,21 @@ function sizeCanvasToContainer(canvas, container, aspect, srcW, srcH) {
|
|
|
1170
1180
|
}
|
|
1171
1181
|
cssW = Math.round(cssW);
|
|
1172
1182
|
cssH = Math.round(cssH);
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
const scale = Math.min(1, MAX_BUF / Math.max(srcW, srcH));
|
|
1177
|
-
bufW = Math.round(srcW * scale);
|
|
1178
|
-
bufH = Math.round(srcH * scale);
|
|
1183
|
+
let renderW, renderH;
|
|
1184
|
+
if (srcW && srcH) {
|
|
1185
|
+
({ renderW, renderH } = computeRenderDims(srcW, srcH));
|
|
1179
1186
|
} else {
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1187
|
+
renderW = cssW;
|
|
1188
|
+
renderH = cssH;
|
|
1189
|
+
}
|
|
1190
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
1191
|
+
const MAX_PX = 8e6;
|
|
1192
|
+
const cappedDpr = renderW * dpr * renderH * dpr > MAX_PX ? Math.sqrt(MAX_PX / (renderW * renderH)) : dpr;
|
|
1193
|
+
canvas.width = Math.round(renderW * cappedDpr);
|
|
1194
|
+
canvas.height = Math.round(renderH * cappedDpr);
|
|
1186
1195
|
canvas.style.width = cssW + "px";
|
|
1187
1196
|
canvas.style.height = cssH + "px";
|
|
1197
|
+
return { renderW, renderH, dpr: cappedDpr };
|
|
1188
1198
|
}
|
|
1189
1199
|
async function asciify(source, canvas, { fontSize, artStyle = "classic", options = {} } = {}) {
|
|
1190
1200
|
let el;
|
|
@@ -1211,8 +1221,20 @@ async function asciify(source, canvas, { fontSize, artStyle = "classic", options
|
|
|
1211
1221
|
const merged = { ...DEFAULT_OPTIONS, ...preset, ...options, fontSize: resolvedFontSize };
|
|
1212
1222
|
const ctx = canvas.getContext("2d");
|
|
1213
1223
|
if (!ctx) throw new Error("Could not get 2d context from canvas");
|
|
1214
|
-
const {
|
|
1215
|
-
|
|
1224
|
+
const { w: srcW, h: srcH } = getSourceDims(el);
|
|
1225
|
+
const { renderW, renderH } = computeRenderDims(srcW, srcH);
|
|
1226
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
1227
|
+
const MAX_PX = 8e6;
|
|
1228
|
+
const cappedDpr = renderW * dpr * renderH * dpr > MAX_PX ? Math.sqrt(MAX_PX / (renderW * renderH)) : dpr;
|
|
1229
|
+
if (canvas.width < renderW || canvas.height < renderH) {
|
|
1230
|
+
canvas.width = Math.round(renderW * cappedDpr);
|
|
1231
|
+
canvas.height = Math.round(renderH * cappedDpr);
|
|
1232
|
+
}
|
|
1233
|
+
const { frame } = imageToAsciiFrame(el, merged, renderW, renderH);
|
|
1234
|
+
ctx.save();
|
|
1235
|
+
ctx.setTransform(cappedDpr, 0, 0, cappedDpr, 0, 0);
|
|
1236
|
+
renderFrameToCanvas(ctx, frame, merged, renderW, renderH);
|
|
1237
|
+
ctx.restore();
|
|
1216
1238
|
}
|
|
1217
1239
|
async function asciifyGif(source, canvas, { fontSize, artStyle = "classic", options = {} } = {}) {
|
|
1218
1240
|
const buffer = typeof source === "string" ? await fetch(source).then((r) => r.arrayBuffer()) : source;
|
|
@@ -1265,15 +1287,26 @@ async function asciifyVideo(source, canvas, { fontSize, artStyle = "classic", op
|
|
|
1265
1287
|
video2 = source;
|
|
1266
1288
|
}
|
|
1267
1289
|
if (container) sizeCanvasToContainer(canvas, container, video2.videoWidth / video2.videoHeight, video2.videoWidth, video2.videoHeight);
|
|
1290
|
+
const { renderW: renderW2, renderH: renderH2 } = computeRenderDims(video2.videoWidth, video2.videoHeight);
|
|
1291
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
1292
|
+
const MAX_PX = 8e6;
|
|
1293
|
+
const cappedDpr = renderW2 * dpr * renderH2 * dpr > MAX_PX ? Math.sqrt(MAX_PX / (renderW2 * renderH2)) : dpr;
|
|
1294
|
+
if (canvas.width < Math.round(renderW2 * cappedDpr)) {
|
|
1295
|
+
canvas.width = Math.round(renderW2 * cappedDpr);
|
|
1296
|
+
canvas.height = Math.round(renderH2 * cappedDpr);
|
|
1297
|
+
}
|
|
1268
1298
|
const maxDur = trimEnd !== void 0 ? trimEnd - trimStart : 10;
|
|
1269
|
-
const { frames, fps } = await videoToAsciiFrames(video2, merged,
|
|
1299
|
+
const { frames, fps } = await videoToAsciiFrames(video2, merged, renderW2, renderH2, void 0, maxDur, void 0, trimStart);
|
|
1270
1300
|
let cancelled2 = false, animId2, i = 0, last = performance.now();
|
|
1271
1301
|
let firstFrame2 = true;
|
|
1272
1302
|
const interval = 1e3 / fps;
|
|
1273
1303
|
const tick2 = (now) => {
|
|
1274
1304
|
if (cancelled2) return;
|
|
1275
1305
|
if (now - last >= interval) {
|
|
1276
|
-
|
|
1306
|
+
ctx.save();
|
|
1307
|
+
ctx.setTransform(cappedDpr, 0, 0, cappedDpr, 0, 0);
|
|
1308
|
+
renderFrameToCanvas(ctx, frames[i], merged, renderW2, renderH2);
|
|
1309
|
+
ctx.restore();
|
|
1277
1310
|
i = (i + 1) % frames.length;
|
|
1278
1311
|
last = now;
|
|
1279
1312
|
if (firstFrame2) {
|
|
@@ -1344,12 +1377,28 @@ async function asciifyVideo(source, canvas, { fontSize, artStyle = "classic", op
|
|
|
1344
1377
|
video.addEventListener("timeupdate", timeupdateHandler);
|
|
1345
1378
|
}
|
|
1346
1379
|
let ro = null;
|
|
1380
|
+
const { renderW, renderH } = computeRenderDims(video.videoWidth, video.videoHeight);
|
|
1347
1381
|
if (container) {
|
|
1348
1382
|
const aspect = video.videoWidth / video.videoHeight;
|
|
1349
1383
|
const vw = video.videoWidth, vh = video.videoHeight;
|
|
1350
|
-
sizeCanvasToContainer(canvas, container, aspect, vw, vh);
|
|
1351
|
-
|
|
1384
|
+
const sizing = sizeCanvasToContainer(canvas, container, aspect, vw, vh);
|
|
1385
|
+
const sCtx = canvas.getContext("2d");
|
|
1386
|
+
if (sCtx) sCtx.setTransform(sizing.dpr, 0, 0, sizing.dpr, 0, 0);
|
|
1387
|
+
ro = new ResizeObserver(() => {
|
|
1388
|
+
const s = sizeCanvasToContainer(canvas, container, aspect, vw, vh);
|
|
1389
|
+
const rCtx = canvas.getContext("2d");
|
|
1390
|
+
if (rCtx) rCtx.setTransform(s.dpr, 0, 0, s.dpr, 0, 0);
|
|
1391
|
+
});
|
|
1352
1392
|
ro.observe(container);
|
|
1393
|
+
} else {
|
|
1394
|
+
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
1395
|
+
const MAX_PX = 8e6;
|
|
1396
|
+
const cappedDpr = renderW * dpr * renderH * dpr > MAX_PX ? Math.sqrt(MAX_PX / (renderW * renderH)) : dpr;
|
|
1397
|
+
if (canvas.width < Math.round(renderW * cappedDpr)) {
|
|
1398
|
+
canvas.width = Math.round(renderW * cappedDpr);
|
|
1399
|
+
canvas.height = Math.round(renderH * cappedDpr);
|
|
1400
|
+
}
|
|
1401
|
+
ctx.setTransform(cappedDpr, 0, 0, cappedDpr, 0, 0);
|
|
1353
1402
|
}
|
|
1354
1403
|
let cancelled = false;
|
|
1355
1404
|
let animId;
|
|
@@ -1360,9 +1409,9 @@ async function asciifyVideo(source, canvas, { fontSize, artStyle = "classic", op
|
|
|
1360
1409
|
if (video.readyState < 2 || canvas.width === 0 || canvas.height === 0) return;
|
|
1361
1410
|
if (trimStart > 0 && video.currentTime < trimStart) return;
|
|
1362
1411
|
if (trimEnd !== void 0 && video.currentTime >= trimEnd) return;
|
|
1363
|
-
const { frame } = imageToAsciiFrame(video, merged,
|
|
1412
|
+
const { frame } = imageToAsciiFrame(video, merged, renderW, renderH);
|
|
1364
1413
|
if (frame.length > 0) {
|
|
1365
|
-
renderFrameToCanvas(ctx, frame, merged,
|
|
1414
|
+
renderFrameToCanvas(ctx, frame, merged, renderW, renderH, 0, null);
|
|
1366
1415
|
if (firstFrame) {
|
|
1367
1416
|
firstFrame = false;
|
|
1368
1417
|
onReady?.(video);
|