Please bookmark this page to avoid losing your image tool!

Image To Video With Audio URL Transition Tool

(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.
/**
 * Creates a video from an image with an optional audio track and transition effect.
 *
 * This async function takes an image object and returns a Promise that resolves 
 * with a playable HTML <video> element.
 *
 * @param {HTMLImageElement} originalImg - The source JavaScript Image object. Its dimensions must be loaded.
 * @param {string} [audioUrl=''] - The URL for the audio track. The server hosting the audio must have CORS enabled. If blank, the video will be silent.
 * @param {string} [transitionType='fade-in'] - Defines the visual transition. Supported values: 'none', 'fade-in', 'zoom-in', 'slide-left', 'slide-right'.
 * @param {number} [duration=5] - The desired duration of the output video in seconds.
 * @returns {Promise<HTMLVideoElement>} A promise that resolves to an HTML video element containing the generated video.
 */
async function processImage(originalImg, audioUrl = '', transitionType = 'fade-in', duration = 5) {

    return new Promise(async (resolve, reject) => {
        try {
            // 1. Setup Canvas to draw frames
            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d');
            canvas.width = originalImg.naturalWidth || originalImg.width;
            canvas.height = originalImg.naturalHeight || originalImg.height;

            if (canvas.width === 0 || canvas.height === 0) {
                 reject(new Error("Image has invalid dimensions (width or height is 0)."));
                 return;
            }

            // 2. Get a video stream from the canvas
            const frameRate = 30; // Use 30 frames per second
            const videoStream = canvas.captureStream(frameRate);
            const [videoTrack] = videoStream.getVideoTracks();

            // 3. Setup audio track if an audioUrl is provided
            let audioTrack = null;
            let audioContext = null;

            if (audioUrl) {
                try {
                    audioContext = new (window.AudioContext || window.webkitAudioContext)();
                    const response = await fetch(audioUrl);
                    if (!response.ok) {
                       throw new Error(`Audio fetch failed with status: ${response.status}`);
                    }
                    const arrayBuffer = await response.arrayBuffer();
                    const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);

                    const audioDestination = audioContext.createMediaStreamDestination();
                    const bufferSource = audioContext.createBufferSource();
                    bufferSource.buffer = audioBuffer;
                    bufferSource.connect(audioDestination);
                    
                    // Start playing the audio into our stream destination, but only for the video's duration
                    bufferSource.start(0, 0, duration);
                    
                    [audioTrack] = audioDestination.stream.getAudioTracks();
                } catch (audioError) {
                    console.warn("Could not process audio URL. The video will be silent.", audioError);
                    // Continue to create a silent video if audio fails
                }
            }

            // 4. Combine video and audio tracks into one stream
            const combinedStream = new MediaStream();
            combinedStream.addTrack(videoTrack);
            if (audioTrack) {
                combinedStream.addTrack(audioTrack);
            }

            // 5. Setup MediaRecorder to record the combined stream
            const supportedTypes = [
                'video/webm;codecs=vp9,opus',
                'video/webm;codecs=vp8,opus',
                'video/webm',
                'video/mp4' // Support is experimental
            ];
            const videoFormat = supportedTypes.find(type => MediaRecorder.isTypeSupported(type));
            
            if (!videoFormat) {
                reject(new Error("No supported video format found for MediaRecorder."));
                return;
            }

            const recorder = new MediaRecorder(combinedStream, { mimeType: videoFormat });
            const chunks = [];

            recorder.ondataavailable = (event) => {
                if (event.data.size > 0) {
                    chunks.push(event.data);
                }
            };

            recorder.onstop = () => {
                // When recording stops, create a blob and a URL for the video
                const blob = new Blob(chunks, { type: videoFormat });
                const videoUrl = URL.createObjectURL(blob);

                // Create the final video element
                const videoElement = document.createElement('video');
                videoElement.src = videoUrl;
                videoElement.controls = true;
                videoElement.autoplay = true;
                videoElement.loop = true;
                videoElement.muted = true; // Autoplay is often blocked by browsers unless muted
                videoElement.style.maxWidth = '100%';
                videoElement.style.maxHeight = '100%';
                
                // Cleanup resources
                videoTrack.stop();
                if (audioTrack) audioTrack.stop();
                if (audioContext && audioContext.state !== 'closed') audioContext.close();
                
                resolve(videoElement);
            };

            recorder.onerror = (event) => {
                reject(event.error || new Error("An unknown MediaRecorder error occurred."));
            };

            // 6. Animation Logic to draw frames onto the canvas
            const startTime = performance.now();
            let animationFrameId;

            const drawFrame = (currentTime) => {
                const elapsedTime = (currentTime - startTime) / 1000;
                
                // Stop the animation and recording when the duration is reached
                if (elapsedTime >= duration) {
                    if (recorder.state === 'recording') {
                         recorder.stop();
                    }
                    cancelAnimationFrame(animationFrameId);
                    return;
                }

                const progress = elapsedTime / duration;

                // Clear canvas with a black background
                ctx.fillStyle = 'black';
                ctx.fillRect(0, 0, canvas.width, canvas.height);
                ctx.save();
                
                // Apply the selected transition effect
                switch (transitionType.toLowerCase()) {
                    case 'fade-in':
                        ctx.globalAlpha = Math.min(1.0, progress * 2); // Fades in over the first half
                        ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
                        break;
                    case 'zoom-in':
                        const scale = 1 + progress * 0.2; // Zooms in by 20% over the duration
                        const newWidth = canvas.width * scale;
                        const newHeight = canvas.height * scale;
                        ctx.drawImage(originalImg, (canvas.width - newWidth) / 2, (canvas.height - newHeight) / 2, newWidth, newHeight);
                        break;
                    case 'slide-left':
                        ctx.drawImage(originalImg, (1 - progress) * canvas.width, 0, canvas.width, canvas.height);
                        break;
                    case 'slide-right':
                        ctx.drawImage(originalImg, -(1 - progress) * canvas.width, 0, canvas.width, canvas.height);
                        break;
                    case 'none':
                    default:
                        ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
                        break;
                }
                ctx.restore();
                
                animationFrameId = requestAnimationFrame(drawFrame);
            };
            
            // 7. Start the recording and the animation loop
            recorder.start();
            animationFrameId = requestAnimationFrame(drawFrame);
            
        } catch (error) {
            console.error("Error creating video:", error);
            reject(error);
        }
    });
}

Free Image Tool Creator

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

Description

The Image To Video With Audio URL Transition Tool allows users to create videos from images with the option to add an audio track and various visual transition effects. Users can specify a duration for the video and choose from transitions such as ‘fade-in’, ‘zoom-in’, and directional slides. This tool is useful for enhancing presentations, creating engaging social media content, or generating dynamic visual introductions for projects by combining static images with motion and sound.

Leave a Reply

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