Please bookmark this page to avoid losing your image tool!

Video Frame To Image Extractor

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, timeExtract = 0, videoUrlOverride = "") {
    return new Promise((resolve) => {
        let isResolved = false;
        let timeoutId;

        // Ensure we only resolve once and clean up easily
        const finalize = (canvas) => {
            if (isResolved) return;
            isResolved = true;
            clearTimeout(timeoutId);
            resolve(canvas);
        };

        // Utility to handle both raw seconds (e.g., 2.5) and timecodes (e.g., "01:23" or "00:01:23.500")
        function parseTimecode(val) {
            if (!val) return 0;
            if (typeof val === 'number') return val;
            const str = String(val).trim();
            if (str.includes(':')) {
                const parts = str.split(':').reverse();
                let secs = 0;
                for (let i = 0; i < parts.length; i++) {
                    secs += (Number(parts[i]) || 0) * Math.pow(60, i);
                }
                return secs;
            }
            return Number(str) || 0;
        }

        // Fallback drawing if the source is not a valid video or cannot be loaded
        const fallbackToImage = () => {
            const canvas = document.createElement('canvas');
            canvas.width = originalImg.naturalWidth || originalImg.width || 800;
            canvas.height = originalImg.naturalHeight || originalImg.height || 600;
            const ctx = canvas.getContext('2d');
            
            if (originalImg.complete && canvas.width > 0 && originalImg.src && !originalImg.src.includes('video')) {
                try {
                    ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
                } catch (e) {
                    console.error("Failed to draw original image as fallback", e);
                }
            } else {
                ctx.fillStyle = "#2c3e50";
                ctx.fillRect(0, 0, canvas.width, canvas.height);
                ctx.fillStyle = "#ecf0f1";
                ctx.font = "24px sans-serif";
                ctx.textAlign = "center";
                ctx.fillText("Provided source is not a playable video.", canvas.width / 2, canvas.height / 2);
            }
            return canvas;
        };

        const video = document.createElement("video");
        video.crossOrigin = "anonymous";
        video.muted = true;
        video.playsInline = true;
        
        video.onerror = () => finalize(fallbackToImage());
        
        // Timeout in case the video hangs on loading/buffering (10 seconds)
        timeoutId = setTimeout(() => {
            finalize(fallbackToImage());
        }, 10000);

        const triggerDraw = () => {
            // Request an animation frame to ensure the video engine has internally updated the frame visual
            requestAnimationFrame(() => {
                const canvas = document.createElement('canvas');
                canvas.width = video.videoWidth || 800;
                canvas.height = video.videoHeight || 600;
                const ctx = canvas.getContext('2d');
                
                // Draw the current video frame onto the canvas
                ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
                finalize(canvas);
            });
        };

        video.onloadeddata = () => {
            let targetTime = parseTimecode(timeExtract);
            if (isNaN(targetTime) || targetTime < 0) targetTime = 0;
            
            // Constrain target time to the actual video duration
            if (!isNaN(video.duration) && video.duration > 0 && targetTime > video.duration) {
                targetTime = Math.max(0, video.duration - 0.1);
            }

            // Check if we are already at the closest frame to prevent pending 'seeked' events
            if (Math.abs(video.currentTime - targetTime) < 0.1) {
                triggerDraw();
            } else {
                video.currentTime = targetTime;
            }
        };

        // When the video seeks to the desired time, exact frame is ready
        video.onseeked = triggerDraw;

        // Obtain source from parameter or inherently fallback to originalImg's src
        // (works natively with base64 Data URIs and Blob URLs of MP4 file uploads)
        const finalSrc = (videoUrlOverride && typeof videoUrlOverride === 'string' && videoUrlOverride.trim() !== "") 
            ? videoUrlOverride 
            : originalImg.src;
            
        if (!finalSrc || finalSrc.trim() === "") {
             finalize(fallbackToImage());
             return;
        }
        
        video.src = finalSrc;
        video.load();
    });
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Video Frame To Image Extractor allows you to capture a high-quality still image from a specific moment in a video. By providing a timestamp or timecode, you can navigate to a precise second in the video and convert that exact frame into a static image. This tool is useful for content creators needing to grab high-resolution screenshots from footage, researchers capturing specific visual data, or anyone looking to extract specific visual elements from video files for use in presentations and social media.

Leave a Reply

Your email address will not be published. Required fields are marked *