Please bookmark this page to avoid losing your image tool!

Image Audio Sync 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 by combining a static image with an audio file.
 * The video will show the static image for the duration of the audio.
 * If no audio is provided, the video will have a specified duration.
 * This function returns a promise that resolves with a playable HTMLVideoElement.
 *
 * @param {HTMLImageElement} originalImg - The loaded JavaScript Image object to use as the video frame.
 * @param {string} [audioUrl=''] - The URL of the audio file to sync with the image.
 *                                 Note: This URL must be from the same origin or a server with
 *                                 permissive CORS policies (e.g., Access-Control-Allow-Origin: *).
 * @param {number} [duration=5] - The duration of the video in seconds. This is only used if an
 *                                audioUrl is not provided or if the audio fails to load.
 * @param {number} [fps=24] - The frames per second for the output video.
 * @returns {Promise<HTMLVideoElement>} A promise that resolves with an HTMLVideoElement containing the generated video.
 */
async function processImage(originalImg, audioUrl = '', duration = 5, fps = 24) {
    // 1. Validate the input image to ensure it's loaded and valid.
    if (!originalImg || !(originalImg instanceof HTMLImageElement) || !originalImg.complete || originalImg.naturalWidth === 0) {
        return Promise.reject(new Error("The provided 'originalImg' is not a valid or fully loaded HTMLImageElement."));
    }

    // 2. Set up a canvas and draw the image onto it. This canvas will be our video source.
    const canvas = document.createElement('canvas');
    canvas.width = originalImg.naturalWidth;
    canvas.height = originalImg.naturalHeight;
    const ctx = canvas.getContext('2d');
    ctx.drawImage(originalImg, 0, 0);

    // 3. Create a video stream from the static canvas.
    const videoStream = canvas.captureStream(fps);
    const [videoTrack] = videoStream.getVideoTracks();

    // 4. Create an audio stream by fetching and decoding the audio file.
    let audioTrack = null;
    let actualDurationMs = duration * 1000; // Default duration in milliseconds.
    const audioContext = new AudioContext();

    if (audioUrl) {
        try {
            const response = await fetch(audioUrl);
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            const arrayBuffer = await response.arrayBuffer();
            const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);

            const audioSource = audioContext.createBufferSource();
            audioSource.buffer = audioBuffer;

            const destinationNode = audioContext.createMediaStreamDestination();
            audioSource.connect(destinationNode);

            [audioTrack] = destinationNode.stream.getAudioTracks();
            actualDurationMs = audioBuffer.duration * 1000; // Use audio's duration.
            audioSource.start(0);
        } catch (e) {
            console.warn(`Could not process audio from ${audioUrl}. Creating a silent video. Error: ${e.message}`);
            // If audio fails, proceed to create a silent video using the default/provided duration.
        }
    }

    // 5. Combine the video and audio tracks (if available) into a single stream.
    const combinedStream = new MediaStream();
    combinedStream.addTrack(videoTrack);
    if (audioTrack) {
        combinedStream.addTrack(audioTrack);
    }

    // 6. Record the combined stream using MediaRecorder. This part is asynchronous and callback-based,
    // so it's wrapped in a Promise.
    return new Promise((resolve, reject) => {
        // A helper function for final resource cleanup.
        const cleanup = () => {
            combinedStream.getTracks().forEach(track => track.stop());
            if (audioContext.state !== 'closed') {
                audioContext.close();
            }
        };
        
        // Find a MIME type that the browser's MediaRecorder supports.
        const mimeTypes = [
            'video/webm; codecs=vp9,opus',
            'video/webm; codecs=vp8,opus',
            'video/webm',
        ];
        const supportedMimeType = mimeTypes.find(type => MediaRecorder.isTypeSupported(type));

        if (!supportedMimeType) {
            cleanup();
            return reject(new Error("No suitable MIME type supported by MediaRecorder for video recording."));
        }

        const recordedChunks = [];
        const mediaRecorder = new MediaRecorder(combinedStream, {
            mimeType: supportedMimeType
        });

        mediaRecorder.ondataavailable = (event) => {
            if (event.data.size > 0) {
                recordedChunks.push(event.data);
            }
        };

        mediaRecorder.onstop = () => {
            const blob = new Blob(recordedChunks, {
                type: supportedMimeType.split(';')[0]
            });
            const videoUrl = URL.createObjectURL(blob);

            const videoElement = document.createElement('video');
            videoElement.src = videoUrl;
            videoElement.controls = true;
            videoElement.width = canvas.width;
            videoElement.height = canvas.height;
            videoElement.style.display = 'block';
            videoElement.style.maxWidth = '100%';

            cleanup();
            resolve(videoElement);
        };

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

        mediaRecorder.start();

        // Stop the recording after the calculated duration.
        setTimeout(() => {
            if (mediaRecorder.state === 'recording') {
                mediaRecorder.stop();
            }
        }, actualDurationMs);
    });
}

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 Audio Sync Tool allows users to create a video by combining a static image with an audio file. This tool is useful for creating visually appealing presentations, slideshows, or social media posts where audio elements enhance the message conveyed by the image. Users can specify the duration of the video, or if provided, the video will sync to the length of the audio track. It is ideal for adding background music to images for personal or professional projects, such as marketing videos or educational materials.

Leave a Reply

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