Please bookmark this page to avoid losing your image tool!

Photo To Movie Converter

(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.
function processImage(originalImg, durationInSeconds = 5, zoomLevel = 1.15, zoomDirection = "in") {
    const container = document.createElement('div');
    container.style.display = 'flex';
    container.style.flexDirection = 'column';
    container.style.alignItems = 'center';
    container.style.justifyContent = 'center';
    container.style.width = '100%';
    container.style.height = '100%';
    container.style.fontFamily = 'system-ui, -apple-system, sans-serif';
    container.style.padding = '20px';
    container.style.boxSizing = 'border-box';
    container.style.background = '#1a1a1a';
    container.style.color = '#ffffff';
    container.style.borderRadius = '8px';
    
    // Header
    const title = document.createElement('h3');
    title.innerText = 'Creating Custom Movie...';
    title.style.margin = '0 0 20px 0';
    container.appendChild(title);

    // Status Message
    const status = document.createElement('div');
    status.style.fontSize = '16px';
    status.style.marginBottom = '10px';
    status.innerText = `Initializing engine...`;
    container.appendChild(status);

    // Progress Bar
    const progressBar = document.createElement('div');
    progressBar.style.width = '100%';
    progressBar.style.maxWidth = '400px';
    progressBar.style.height = '8px';
    progressBar.style.background = '#333';
    progressBar.style.borderRadius = '4px';
    progressBar.style.overflow = 'hidden';
    
    const progressFill = document.createElement('div');
    progressFill.style.width = '0%';
    progressFill.style.height = '100%';
    progressFill.style.background = '#4CAF50';
    progressFill.style.transition = 'width 0.1s linear';
    progressBar.appendChild(progressFill);
    container.appendChild(progressBar);

    const duration = parseFloat(durationInSeconds);
    const intensity = parseFloat(zoomLevel);
    const fps = 30;

    const canvas = document.createElement('canvas');
    
    // Set size constraint for optimal video processing client-side
    const maxWidth = 1280;
    const maxHeight = 1280;
    let width = originalImg.width;
    let height = originalImg.height;

    if (width > maxWidth || height > maxHeight) {
        const ratio = Math.min(maxWidth / width, maxHeight / height);
        width = Math.floor(width * ratio);
        height = Math.floor(height * ratio);
    }
    
    // Make dimensions even numbers (required by some encoders)
    canvas.width = width - (width % 2);
    canvas.height = height - (height % 2);
    const ctx = canvas.getContext('2d');
    
    // Initialize video stream
    const captureStream = canvas.captureStream || canvas.mozCaptureStream;
    if (!captureStream) {
        status.innerText = "Error: Video capturing stream is not supported in this browser.";
        progressBar.style.display = 'none';
        return container;
    }
    
    const stream = captureStream.call(canvas, fps);
    
    let mimeType = '';
    const types = [
        'video/webm;codecs=vp9',
        'video/webm;codecs=vp8',
        'video/webm',
        'video/mp4;codecs=avc1',
        'video/mp4'
    ];
    
    if (typeof MediaRecorder !== 'undefined') {
        for (const type of types) {
            if (MediaRecorder.isTypeSupported(type)) {
                mimeType = type;
                break;
            }
        }
    }
    
    if (typeof MediaRecorder === 'undefined' || !mimeType) {
        status.innerText = "Error: MediaRecorder API not supported or no compatible format found.";
        progressBar.style.display = 'none';
        return container;
    }
    
    const recorder = new MediaRecorder(stream, { mimeType });
    const chunks = [];
    
    recorder.ondataavailable = e => {
        if (e.data && e.data.size > 0) chunks.push(e.data);
    };
    
    recorder.onstop = () => {
        const blob = new Blob(chunks, { type: mimeType });
        const video = document.createElement('video');
        video.controls = true;
        video.autoplay = true;
        video.loop = true;
        video.style.maxWidth = '100%';
        video.style.maxHeight = '70vh';
        video.style.borderRadius = '8px';
        video.style.boxShadow = '0 6px 20px rgba(0,0,0,0.6)';
        video.src = URL.createObjectURL(blob);
        
        status.style.display = 'none';
        progressBar.style.display = 'none';
        title.style.display = 'none';
        
        const controlsDiv = document.createElement('div');
        controlsDiv.style.marginTop = '20px';
        controlsDiv.style.display = 'flex';
        controlsDiv.style.gap = '10px';
        
        const dlBtn = document.createElement('a');
        const extension = mimeType.includes('mp4') ? 'mp4' : 'webm';
        dlBtn.href = video.src;
        dlBtn.download = `photo_movie_${Date.now()}.${extension}`;
        dlBtn.innerText = 'Download Movie';
        dlBtn.style.padding = '12px 24px';
        dlBtn.style.background = '#4CAF50';
        dlBtn.style.color = '#fff';
        dlBtn.style.textDecoration = 'none';
        dlBtn.style.borderRadius = '6px';
        dlBtn.style.fontWeight = 'bold';
        dlBtn.style.cursor = 'pointer';
        dlBtn.style.transition = 'background 0.2s';
        
        dlBtn.onmouseover = () => dlBtn.style.background = '#45a049';
        dlBtn.onmouseout = () => dlBtn.style.background = '#4CAF50';
        
        controlsDiv.appendChild(dlBtn);
        container.appendChild(video);
        container.appendChild(controlsDiv);
    };
    
    try {
        recorder.start();
    } catch (err) {
        status.innerText = "Error: Could not start recording. This may be due to cross-origin image constraints.";
        progressBar.style.display = 'none';
        return container;
    }
    
    // Ken Burns Animation Setup
    const isZoomIn = zoomDirection.toLowerCase() === "in";
    const scaleStart = isZoomIn ? 1.0 : intensity;
    const scaleEnd = isZoomIn ? intensity : 1.0;
    
    const panX = 0.04 * canvas.width;
    const panY = 0.04 * canvas.height;
    
    let startTime = null;
    
    const drawFrame = (timestamp) => {
        if (!startTime) startTime = timestamp;
        const elapsed = timestamp - startTime;
        let progress = elapsed / (duration * 1000);
        
        if (progress > 1.0) progress = 1.0;
        
        // Easing function for smoother motion
        const easeProgress = progress < 0.5 ? 2 * progress * progress : -1 + (4 - 2 * progress) * progress;
        
        const scale = scaleStart + (scaleEnd - scaleStart) * easeProgress;
        const dx = (isZoomIn ? -panX : panX) * easeProgress;
        const dy = (isZoomIn ? -panY : panY) * easeProgress;
        
        ctx.fillStyle = '#000';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        
        ctx.save();
        ctx.translate(canvas.width / 2, canvas.height / 2);
        ctx.scale(scale, scale);
        ctx.translate(-canvas.width / 2, -canvas.height / 2);
        ctx.translate(dx, dy);
        
        ctx.imageSmoothingEnabled = true;
        ctx.imageSmoothingQuality = 'high';
        ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
        ctx.restore();
        
        const pct = Math.round(progress * 100);
        status.innerText = `Recording movie: ${pct}%`;
        progressFill.style.width = `${pct}%`;
        
        if (progress >= 1.0) {
            recorder.stop();
            return;
        }
        
        requestAnimationFrame(drawFrame);
    };
    
    // Draw initial frame and commence rendering
    ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
    requestAnimationFrame(drawFrame);
    
    return container;
}

Free Image Tool Creator

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

Description

The Photo To Movie Converter transforms static images into dynamic video clips by applying the Ken Burns effect, which includes smooth zooming and panning animations. Users can customize the video duration and the intensity and direction of the zoom. This tool is ideal for creating engaging social media content, enhancing photo slideshows, or adding cinematic movement to still photographs for presentations and digital storytelling.

Leave a Reply

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