e308adc642
- Add package.json with dependencies for React, Vite, and TypeScript. - Create main application structure in App.tsx for video loading and frame analysis. - Implement video scanning logic to identify candidate frames based on visual changes. - Add candidate ranking and trimming functionality to optimize selected frames. - Develop media handling utilities for capturing frames and managing video playback. - Introduce clipboard functionality for copying and downloading frames. - Design user interface with responsive styles for video selection and analysis controls. - Establish TypeScript types for video loading, scan settings, and candidate frames. - Configure TypeScript and Vite for project compilation and development.
71 lines
2.0 KiB
TypeScript
71 lines
2.0 KiB
TypeScript
import { seekVideo } from "./video";
|
|
|
|
export function captureAnalysisFrame(
|
|
video: HTMLVideoElement,
|
|
canvas: HTMLCanvasElement,
|
|
width: number,
|
|
height: number,
|
|
): ImageData {
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
|
|
const context = canvas.getContext("2d", { willReadFrequently: true });
|
|
if (!context) throw new Error("Could not create the analysis canvas context.");
|
|
|
|
context.drawImage(video, 0, 0, width, height);
|
|
return context.getImageData(0, 0, width, height);
|
|
}
|
|
|
|
export async function createThumbnailUrl(video: HTMLVideoElement, maxWidth = 360): Promise<string> {
|
|
const scale = Math.min(1, maxWidth / video.videoWidth);
|
|
const width = Math.max(1, Math.round(video.videoWidth * scale));
|
|
const height = Math.max(1, Math.round(video.videoHeight * scale));
|
|
const canvas = document.createElement("canvas");
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
|
|
const context = canvas.getContext("2d");
|
|
if (!context) throw new Error("Could not create thumbnail canvas context.");
|
|
|
|
context.drawImage(video, 0, 0, width, height);
|
|
|
|
const blob = await canvasToBlob(canvas, "image/webp", 0.82);
|
|
return URL.createObjectURL(blob);
|
|
}
|
|
|
|
export async function extractFullResolutionFrame(
|
|
video: HTMLVideoElement,
|
|
time: number,
|
|
type: "image/png" | "image/jpeg" | "image/webp" = "image/png",
|
|
quality?: number,
|
|
): Promise<Blob> {
|
|
await seekVideo(video, time);
|
|
|
|
const canvas = document.createElement("canvas");
|
|
canvas.width = video.videoWidth;
|
|
canvas.height = video.videoHeight;
|
|
|
|
const context = canvas.getContext("2d");
|
|
if (!context) throw new Error("Could not create full-resolution canvas context.");
|
|
|
|
context.drawImage(video, 0, 0);
|
|
return canvasToBlob(canvas, type, quality);
|
|
}
|
|
|
|
export async function canvasToBlob(
|
|
canvas: HTMLCanvasElement,
|
|
type: string,
|
|
quality?: number,
|
|
): Promise<Blob> {
|
|
return new Promise((resolve, reject) => {
|
|
canvas.toBlob(
|
|
(blob) => {
|
|
if (!blob) reject(new Error("Canvas export failed."));
|
|
else resolve(blob);
|
|
},
|
|
type,
|
|
quality,
|
|
);
|
|
});
|
|
}
|