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!
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.