You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, dubbingText = "Hello! This is an AI simulated video dubbing and translation. Click here to play.", languageCode = "en-US", fontSize = 32, fontColor = "#FEFEFE") {
// Create an interactive container for our "video" mockup
const container = document.createElement('div');
container.style.position = 'relative';
container.style.display = 'inline-block';
container.style.maxWidth = '100%';
container.style.cursor = 'pointer';
container.title = 'Click to play/pause AI dubbing audio';
// Create the canvas rendering the mock video frame
const canvas = document.createElement('canvas');
const width = originalImg.width;
const height = originalImg.height;
canvas.width = width;
canvas.height = height;
canvas.style.maxWidth = '100%';
canvas.style.height = 'auto';
canvas.style.display = 'block';
canvas.style.borderRadius = '8px';
canvas.style.boxShadow = '0 4px 12px rgba(0,0,0,0.3)';
const ctx = canvas.getContext('2d');
// Draw the original image as the background video frame
ctx.drawImage(originalImg, 0, 0);
// Apply a subtle darkening vignette layer for video realism
ctx.fillStyle = "rgba(0, 0, 0, 0.35)";
ctx.fillRect(0, 0, width, height);
// Draw the Play Button Overlay
const minDim = Math.min(width, height);
const centerX = width / 2;
const centerY = height / 2;
const radius = minDim * 0.12;
// Play button background
ctx.fillStyle = "rgba(0, 0, 0, 0.65)";
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
ctx.fill();
ctx.lineWidth = 3;
ctx.strokeStyle = "rgba(255, 255, 255, 0.8)";
ctx.stroke();
// Play button triangle
ctx.fillStyle = "rgba(255, 255, 255, 0.95)";
ctx.beginPath();
const iconSize = radius * 0.45;
ctx.moveTo(centerX - iconSize * 0.4, centerY - iconSize);
ctx.lineTo(centerX + iconSize, centerY);
ctx.lineTo(centerX - iconSize * 0.4, centerY + iconSize);
ctx.closePath();
ctx.fill();
// Prepare Subtitle Text Parameters
let parsedFontSize = parseInt(String(fontSize), 10) || 32;
// Scale font safely based on image height to avoid overflow issues on small images
parsedFontSize = Math.min(parsedFontSize, Math.max(12, Math.floor(height * 0.08)));
ctx.font = `bold ${parsedFontSize}px Arial, sans-serif`;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
const maxWidth = width * 0.90;
const words = String(dubbingText).split(' ');
let currentLine = "";
const lines = [];
// Word Wrap Logic for Subtitles
for(let i = 0; i < words.length; i++) {
const testLine = currentLine + words[i] + " ";
const metrics = ctx.measureText(testLine);
if (metrics.width > maxWidth && i > 0) {
lines.push(currentLine.trim());
currentLine = words[i] + " ";
} else {
currentLine = testLine;
}
}
lines.push(currentLine.trim());
// Subtitle Container Layout
const lineHeight = parsedFontSize * 1.4;
const padding = Math.max(10, parsedFontSize * 0.5);
const marginB = Math.max(height * 0.06, 20);
let maxLineWidth = 0;
for (let line of lines) {
maxLineWidth = Math.max(maxLineWidth, ctx.measureText(line).width);
}
const boxWidth = Math.min(maxLineWidth + padding * 4, width * 0.95);
const boxHeight = lines.length * lineHeight + padding * 2;
const boxX = (width - boxWidth) / 2;
const boxY = height - marginB - boxHeight;
// Draw Subtitle Background
ctx.fillStyle = "rgba(0, 0, 0, 0.75)";
if (ctx.roundRect) {
ctx.beginPath();
ctx.roundRect(boxX, boxY, boxWidth, boxHeight, 12);
ctx.fill();
} else {
ctx.fillRect(boxX, boxY, boxWidth, boxHeight);
}
// Draw Subtitle Text Lines
ctx.fillStyle = fontColor || "#FFFFFF";
let textY = boxY + padding + (lineHeight / 2);
for (let i = 0; i < lines.length; i++) {
ctx.fillText(lines[i], centerX, textY);
textY += lineHeight;
}
// Add Canvas to Output Container
container.appendChild(canvas);
// Audio Playback Integration (Web Speech API)
let isPlaying = false;
container.addEventListener('click', () => {
if (!('speechSynthesis' in window)) {
alert("Text-to-Speech is not supported in your current browser.");
return;
}
// Toggle pause/play behavior
if (isPlaying) {
window.speechSynthesis.cancel();
isPlaying = false;
return;
}
window.speechSynthesis.cancel();
const utterance = new SpeechSynthesisUtterance(String(dubbingText));
utterance.lang = String(languageCode);
utterance.rate = 0.9; // Slightly slower for dubbing feels
// Ensure best voice match
const applyVoice = () => {
const voices = window.speechSynthesis.getVoices();
if (voices.length > 0) {
let match = voices.find(v => v.lang.toLowerCase() === utterance.lang.toLowerCase());
if (!match) {
match = voices.find(v => v.lang.split('-')[0].toLowerCase() === utterance.lang.split('-')[0].toLowerCase());
}
if (match) utterance.voice = match;
}
};
applyVoice();
if (window.speechSynthesis.getVoices().length === 0) {
window.speechSynthesis.onvoiceschanged = applyVoice;
}
utterance.onstart = () => { isPlaying = true; };
utterance.onend = () => { isPlaying = false; };
utterance.onerror = () => { isPlaying = false; };
window.speechSynthesis.speak(utterance);
});
return container;
}
Apply Changes