You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, targetLanguage = "Russian", subtitleText = "Auto-Dubbing Translator Active", themeColor = "#ff0000") {
// Determine canvas dimensions
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const w = originalImg.width;
const h = originalImg.height;
canvas.width = w;
canvas.height = h;
// Draw original image as the background
ctx.drawImage(originalImg, 0, 0, w, h);
// Calculate a stable scale factor for UI elements
// Ensuring UI doesn't get ridiculously small on tiny images
const scale = Math.max(w / 1280, 0.5);
// 1. Draw bottom vignette/gradient for good UI visibility
const grad = ctx.createLinearGradient(0, h - (200 * scale), 0, h);
grad.addColorStop(0, 'rgba(0,0,0,0)');
grad.addColorStop(0.5, 'rgba(0,0,0,0.5)');
grad.addColorStop(1, 'rgba(0,0,0,0.85)');
ctx.fillStyle = grad;
ctx.fillRect(0, h - (200 * scale), w, 200 * scale);
// 2. Draw Subtitles
if (subtitleText) {
ctx.font = `bold ${Math.floor(36 * scale)}px Arial, sans-serif`;
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
const subY = h - (65 * scale);
// Draw subtitle background/shadow for legibility
ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
const textWidth = ctx.measureText(subtitleText).width;
ctx.fillRect((w / 2) - (textWidth / 2) - (15 * scale), subY - (36 * scale) - (10 * scale), textWidth + (30 * scale), 46 * scale);
ctx.fillStyle = 'white';
ctx.fillText(subtitleText, w / 2, subY);
}
// 3. YouTube-style UI Bottom Bar
const barY = h - (20 * scale);
const barPadding = 20 * scale;
const barWidth = w - (barPadding * 2);
// Background track line
ctx.fillStyle = 'rgba(255, 255, 255, 0.2)';
ctx.fillRect(barPadding, barY, barWidth, 4 * scale);
// Buffered track line
ctx.fillStyle = 'rgba(255, 255, 255, 0.4)';
ctx.fillRect(barPadding, barY, barWidth * 0.6, 4 * scale);
// Primary progress line (colored)
ctx.fillStyle = themeColor;
ctx.fillRect(barPadding, barY, barWidth * 0.4, 4 * scale);
// Playhead dot
ctx.beginPath();
ctx.arc(barPadding + (barWidth * 0.4), barY + (2 * scale), 7 * scale, 0, Math.PI * 2);
ctx.fill();
// 4. UI Icons (Play, Volume, Time, Gear, Fullscreen) using Unicode
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
ctx.font = `${Math.floor(20 * scale)}px Arial, sans-serif`;
ctx.fillStyle = 'white';
// Left icons
const iconsY = h - (40 * scale);
ctx.fillText("▶ 🔊 3:42 / 10:15", barPadding, iconsY);
// Right icons
ctx.textAlign = 'right';
// Gear, CC, square
ctx.fillText("⚙ CC 🔲", w - barPadding, iconsY);
// Helper for Drawing Rounded Rectangles
function drawRoundRect(x, y, width, height, radius) {
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
}
// 5. "Audio Track" settings menu popup
const menuWidth = 320 * scale;
const menuHeight = 160 * scale;
const menuX = w - barPadding - menuWidth - (30 * scale);
const menuY = h - menuHeight - (70 * scale);
ctx.fillStyle = 'rgba(28, 28, 28, 0.95)';
drawRoundRect(menuX, menuY, menuWidth, menuHeight, 12 * scale);
ctx.fill();
// Menu content
ctx.textAlign = 'left';
// Header
ctx.font = `normal ${Math.floor(18 * scale)}px Arial, sans-serif`;
ctx.fillStyle = '#aaaaaa';
ctx.fillText("Audio track", menuX + (20 * scale), menuY + (30 * scale));
// Divider line
ctx.fillStyle = 'rgba(255, 255, 255, 0.1)';
ctx.fillRect(menuX, menuY + (50 * scale), menuWidth, 1 * scale);
// Option 1: Original Language
ctx.font = `normal ${Math.floor(20 * scale)}px Arial, sans-serif`;
ctx.fillStyle = '#ffffff';
ctx.fillText("English (Original)", menuX + (45 * scale), menuY + (80 * scale));
// Option 2: Target Translated Language
ctx.fillText(`${targetLanguage} (Dubbed)`, menuX + (45 * scale), menuY + (125 * scale));
// Checkmark for active track
ctx.fillStyle = themeColor === "#ff0000" ? "#3ea6ff" : themeColor;
ctx.fillText("✓", menuX + (20 * scale), menuY + (125 * scale));
// 6. "Auto-Dubbing Active" Waveform Indicator (Top left)
const waveW = 280 * scale;
const waveH = 50 * scale;
const waveX = 30 * scale;
const waveY = 30 * scale;
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
drawRoundRect(waveX, waveY, waveW, waveH, 25 * scale);
ctx.fill();
// Audio Waves rendering
ctx.fillStyle = '#10B981'; // vibrant green to indicate translation is live
const bars = [10, 24, 15, 30, 18, 12, 22];
for (let i = 0; i < bars.length; i++) {
const barH = bars[i] * scale;
const barW = 4 * scale;
const bX = waveX + (25 * scale) + (i * 8 * scale);
const bY = waveY + (waveH / 2) - (barH / 2);
ctx.beginPath();
ctx.roundRect ? ctx.roundRect(bX, bY, barW, barH, 2 * scale) : ctx.fillRect(bX, bY, barW, barH);
ctx.fill();
}
// Text for indicator
ctx.font = `bold ${Math.floor(18 * scale)}px Arial, sans-serif`;
ctx.fillStyle = '#ffffff';
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
ctx.fillText("Auto-Dub Translator", waveX + (95 * scale), waveY + (waveH / 2));
return canvas;
}
Apply Changes