asciify-engine 1.0.69 → 1.0.70

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 CHANGED
@@ -1162,6 +1162,25 @@ 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 makeHiResCanvas(srcW, srcH, displayW, displayH) {
1171
+ if (srcW <= displayW && srcH <= displayH) return null;
1172
+ const MAX = 2048;
1173
+ const scale = Math.min(1, MAX / Math.max(srcW, srcH));
1174
+ const offW = Math.round(srcW * scale);
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 };
1183
+ }
1165
1184
  function sizeCanvasToContainer(canvas, container, aspect, srcW, srcH) {
1166
1185
  const { width, height } = container.getBoundingClientRect();
1167
1186
  if (!width || !height) return;
@@ -1213,8 +1232,17 @@ async function asciify(source, canvas, { fontSize, artStyle = "classic", options
1213
1232
  const merged = { ...DEFAULT_OPTIONS, ...preset, ...options, fontSize: resolvedFontSize };
1214
1233
  const ctx = canvas.getContext("2d");
1215
1234
  if (!ctx) throw new Error("Could not get 2d context from canvas");
1216
- const { frame } = imageToAsciiFrame(el, merged, canvas.width, canvas.height);
1217
- renderFrameToCanvas(ctx, frame, merged, canvas.width, canvas.height);
1235
+ const { w: srcW, h: srcH } = getSourceDims(el);
1236
+ const hires = makeHiResCanvas(srcW, srcH, canvas.width, canvas.height);
1237
+ if (hires) {
1238
+ const { frame } = imageToAsciiFrame(el, merged, hires.offW, hires.offH);
1239
+ renderFrameToCanvas(hires.offCtx, frame, merged, hires.offW, hires.offH);
1240
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
1241
+ ctx.drawImage(hires.offCanvas, 0, 0, canvas.width, canvas.height);
1242
+ } else {
1243
+ const { frame } = imageToAsciiFrame(el, merged, canvas.width, canvas.height);
1244
+ renderFrameToCanvas(ctx, frame, merged, canvas.width, canvas.height);
1245
+ }
1218
1246
  }
1219
1247
  async function asciifyGif(source, canvas, { fontSize, artStyle = "classic", options = {} } = {}) {
1220
1248
  const buffer = typeof source === "string" ? await fetch(source).then((r) => r.arrayBuffer()) : source;
@@ -1267,15 +1295,24 @@ async function asciifyVideo(source, canvas, { fontSize, artStyle = "classic", op
1267
1295
  video2 = source;
1268
1296
  }
1269
1297
  if (container) sizeCanvasToContainer(canvas, container, video2.videoWidth / video2.videoHeight, video2.videoWidth, video2.videoHeight);
1298
+ const hires2 = makeHiResCanvas(video2.videoWidth, video2.videoHeight, canvas.width, canvas.height);
1299
+ const renderW = hires2 ? hires2.offW : canvas.width;
1300
+ const renderH = hires2 ? hires2.offH : canvas.height;
1270
1301
  const maxDur = trimEnd !== void 0 ? trimEnd - trimStart : 10;
1271
- const { frames, fps } = await videoToAsciiFrames(video2, merged, canvas.width, canvas.height, void 0, maxDur, void 0, trimStart);
1302
+ const { frames, fps } = await videoToAsciiFrames(video2, merged, renderW, renderH, void 0, maxDur, void 0, trimStart);
1272
1303
  let cancelled2 = false, animId2, i = 0, last = performance.now();
1273
1304
  let firstFrame2 = true;
1274
1305
  const interval = 1e3 / fps;
1275
1306
  const tick2 = (now) => {
1276
1307
  if (cancelled2) return;
1277
1308
  if (now - last >= interval) {
1278
- renderFrameToCanvas(ctx, frames[i], merged, canvas.width, canvas.height);
1309
+ if (hires2) {
1310
+ renderFrameToCanvas(hires2.offCtx, frames[i], merged, hires2.offW, hires2.offH);
1311
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
1312
+ ctx.drawImage(hires2.offCanvas, 0, 0, canvas.width, canvas.height);
1313
+ } else {
1314
+ renderFrameToCanvas(ctx, frames[i], merged, canvas.width, canvas.height);
1315
+ }
1279
1316
  i = (i + 1) % frames.length;
1280
1317
  last = now;
1281
1318
  if (firstFrame2) {
@@ -1353,6 +1390,7 @@ async function asciifyVideo(source, canvas, { fontSize, artStyle = "classic", op
1353
1390
  ro = new ResizeObserver(() => sizeCanvasToContainer(canvas, container, aspect, vw, vh));
1354
1391
  ro.observe(container);
1355
1392
  }
1393
+ const hires = makeHiResCanvas(video.videoWidth, video.videoHeight, canvas.width, canvas.height);
1356
1394
  let cancelled = false;
1357
1395
  let animId;
1358
1396
  let firstFrame = true;
@@ -1362,14 +1400,28 @@ async function asciifyVideo(source, canvas, { fontSize, artStyle = "classic", op
1362
1400
  if (video.readyState < 2 || canvas.width === 0 || canvas.height === 0) return;
1363
1401
  if (trimStart > 0 && video.currentTime < trimStart) return;
1364
1402
  if (trimEnd !== void 0 && video.currentTime >= trimEnd) return;
1365
- const { frame } = imageToAsciiFrame(video, merged, canvas.width, canvas.height);
1366
- if (frame.length > 0) {
1367
- renderFrameToCanvas(ctx, frame, merged, canvas.width, canvas.height, 0, null);
1368
- if (firstFrame) {
1369
- firstFrame = false;
1370
- onReady?.(video);
1403
+ if (hires) {
1404
+ const { frame } = imageToAsciiFrame(video, merged, hires.offW, hires.offH);
1405
+ if (frame.length > 0) {
1406
+ renderFrameToCanvas(hires.offCtx, frame, merged, hires.offW, hires.offH, 0, null);
1407
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
1408
+ ctx.drawImage(hires.offCanvas, 0, 0, canvas.width, canvas.height);
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?.();
1371
1424
  }
1372
- onFrame?.();
1373
1425
  }
1374
1426
  };
1375
1427
  animId = requestAnimationFrame(tick);