asciify-engine 1.0.48 → 1.0.50
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 +37 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +37 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -694,15 +694,15 @@ function imageToAsciiFrame(source, options, targetWidth, targetHeight) {
|
|
|
694
694
|
}
|
|
695
695
|
return { frame, cols, rows };
|
|
696
696
|
}
|
|
697
|
-
async function videoToAsciiFrames(video, options, targetWidth, targetHeight, targetFps = 12, maxDuration = 10, onProgress) {
|
|
698
|
-
const duration = Math.min(video.duration, maxDuration);
|
|
697
|
+
async function videoToAsciiFrames(video, options, targetWidth, targetHeight, targetFps = 12, maxDuration = 10, onProgress, startTime = 0) {
|
|
698
|
+
const duration = Math.min(video.duration - startTime, maxDuration);
|
|
699
699
|
const totalFrames = Math.ceil(duration * targetFps);
|
|
700
700
|
const frames = [];
|
|
701
701
|
let cols = 0;
|
|
702
702
|
let rows = 0;
|
|
703
703
|
for (let i = 0; i < totalFrames; i++) {
|
|
704
|
-
const time = i / targetFps;
|
|
705
|
-
if (time > duration) break;
|
|
704
|
+
const time = startTime + i / targetFps;
|
|
705
|
+
if (time > startTime + duration) break;
|
|
706
706
|
video.currentTime = time;
|
|
707
707
|
await new Promise((resolve) => {
|
|
708
708
|
const handler = () => {
|
|
@@ -1089,7 +1089,9 @@ async function asciifyGif(source, canvas, { fontSize = 10, artStyle = "classic",
|
|
|
1089
1089
|
cancelAnimationFrame(animId);
|
|
1090
1090
|
};
|
|
1091
1091
|
}
|
|
1092
|
-
async function asciifyVideo(source, canvas, { fontSize = 10, artStyle = "classic", options = {}, fitTo, preExtract = false, onReady, onFrame } = {}) {
|
|
1092
|
+
async function asciifyVideo(source, canvas, { fontSize = 10, artStyle = "classic", options = {}, fitTo, preExtract = false, trim, onReady, onFrame } = {}) {
|
|
1093
|
+
const trimStart = trim?.start ?? 0;
|
|
1094
|
+
const trimEnd = trim?.end;
|
|
1093
1095
|
const merged = { ...DEFAULT_OPTIONS, ...ART_STYLE_PRESETS[artStyle], ...options, fontSize };
|
|
1094
1096
|
const ctx = canvas.getContext("2d");
|
|
1095
1097
|
if (!ctx) throw new Error("asciifyVideo: could not get 2d context from canvas.");
|
|
@@ -1110,9 +1112,10 @@ async function asciifyVideo(source, canvas, { fontSize = 10, artStyle = "classic
|
|
|
1110
1112
|
video2 = source;
|
|
1111
1113
|
}
|
|
1112
1114
|
if (container) sizeCanvasToContainer(canvas, container, video2.videoWidth / video2.videoHeight);
|
|
1113
|
-
|
|
1114
|
-
const { frames, fps } = await videoToAsciiFrames(video2, merged, canvas.width, canvas.height);
|
|
1115
|
+
const maxDur = trimEnd !== void 0 ? trimEnd - trimStart : 10;
|
|
1116
|
+
const { frames, fps } = await videoToAsciiFrames(video2, merged, canvas.width, canvas.height, void 0, maxDur, void 0, trimStart);
|
|
1115
1117
|
let cancelled2 = false, animId2, i = 0, last = performance.now();
|
|
1118
|
+
let firstFrame2 = true;
|
|
1116
1119
|
const interval = 1e3 / fps;
|
|
1117
1120
|
const tick2 = (now) => {
|
|
1118
1121
|
if (cancelled2) return;
|
|
@@ -1120,6 +1123,10 @@ async function asciifyVideo(source, canvas, { fontSize = 10, artStyle = "classic
|
|
|
1120
1123
|
renderFrameToCanvas(ctx, frames[i], merged, canvas.width, canvas.height);
|
|
1121
1124
|
i = (i + 1) % frames.length;
|
|
1122
1125
|
last = now;
|
|
1126
|
+
if (firstFrame2) {
|
|
1127
|
+
firstFrame2 = false;
|
|
1128
|
+
onReady?.(video2);
|
|
1129
|
+
}
|
|
1123
1130
|
onFrame?.();
|
|
1124
1131
|
}
|
|
1125
1132
|
animId2 = requestAnimationFrame(tick2);
|
|
@@ -1162,6 +1169,23 @@ async function asciifyVideo(source, canvas, { fontSize = 10, artStyle = "classic
|
|
|
1162
1169
|
if (video.paused) await video.play().catch(() => {
|
|
1163
1170
|
});
|
|
1164
1171
|
}
|
|
1172
|
+
if (trimStart > 0) {
|
|
1173
|
+
video.currentTime = trimStart;
|
|
1174
|
+
await new Promise((resolve) => {
|
|
1175
|
+
const h = () => {
|
|
1176
|
+
video.removeEventListener("seeked", h);
|
|
1177
|
+
resolve();
|
|
1178
|
+
};
|
|
1179
|
+
video.addEventListener("seeked", h);
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
let timeupdateHandler = null;
|
|
1183
|
+
if (trimEnd !== void 0) {
|
|
1184
|
+
timeupdateHandler = () => {
|
|
1185
|
+
if (video.currentTime >= trimEnd) video.currentTime = trimStart;
|
|
1186
|
+
};
|
|
1187
|
+
video.addEventListener("timeupdate", timeupdateHandler);
|
|
1188
|
+
}
|
|
1165
1189
|
let ro = null;
|
|
1166
1190
|
if (container) {
|
|
1167
1191
|
const aspect = video.videoWidth / video.videoHeight;
|
|
@@ -1169,9 +1193,9 @@ async function asciifyVideo(source, canvas, { fontSize = 10, artStyle = "classic
|
|
|
1169
1193
|
ro = new ResizeObserver(() => sizeCanvasToContainer(canvas, container, aspect));
|
|
1170
1194
|
ro.observe(container);
|
|
1171
1195
|
}
|
|
1172
|
-
onReady?.(video);
|
|
1173
1196
|
let cancelled = false;
|
|
1174
1197
|
let animId;
|
|
1198
|
+
let firstFrame = true;
|
|
1175
1199
|
const tick = () => {
|
|
1176
1200
|
if (cancelled) return;
|
|
1177
1201
|
animId = requestAnimationFrame(tick);
|
|
@@ -1179,6 +1203,10 @@ async function asciifyVideo(source, canvas, { fontSize = 10, artStyle = "classic
|
|
|
1179
1203
|
const { frame } = imageToAsciiFrame(video, merged, canvas.width, canvas.height);
|
|
1180
1204
|
if (frame.length > 0) {
|
|
1181
1205
|
renderFrameToCanvas(ctx, frame, merged, canvas.width, canvas.height, 0, null);
|
|
1206
|
+
if (firstFrame) {
|
|
1207
|
+
firstFrame = false;
|
|
1208
|
+
onReady?.(video);
|
|
1209
|
+
}
|
|
1182
1210
|
onFrame?.();
|
|
1183
1211
|
}
|
|
1184
1212
|
};
|
|
@@ -1187,6 +1215,7 @@ async function asciifyVideo(source, canvas, { fontSize = 10, artStyle = "classic
|
|
|
1187
1215
|
cancelled = true;
|
|
1188
1216
|
cancelAnimationFrame(animId);
|
|
1189
1217
|
ro?.disconnect();
|
|
1218
|
+
if (timeupdateHandler) video.removeEventListener("timeupdate", timeupdateHandler);
|
|
1190
1219
|
if (ownedVideo) {
|
|
1191
1220
|
video.pause();
|
|
1192
1221
|
video.src = "";
|