You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, videoTitle = "Amazing Video", timestamp = "10:00") {
const canvas = document.createElement('canvas');
canvas.width = originalImg.width;
canvas.height = originalImg.height;
const ctx = canvas.getContext('2d');
// Draw original background image
ctx.drawImage(originalImg, 0, 0);
const w = canvas.width;
const h = canvas.height;
// Calculate a scale factor based on resolution to keep UI proportional
// Capped min at 0.2 to prevent zero/negative sizes, scales responsively up to available size.
const s = Math.max(0.2, Math.min(w / 1000, h / 600));
// Helper to draw rounded rectangles
function drawRoundRect(ctx, 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();
}
// --- 1. Top Gradient and Title UI ---
const gradTop = ctx.createLinearGradient(0, 0, 0, 120 * s);
gradTop.addColorStop(0, 'rgba(0,0,0,0.8)');
gradTop.addColorStop(1, 'rgba(0,0,0,0)');
ctx.fillStyle = gradTop;
ctx.fillRect(0, 0, w, 120 * s);
// Channel Avatar Placeholder
const avatarX = 20 * s;
const avatarY = 20 * s;
const avatarR = 18 * s;
ctx.fillStyle = '#FF5722';
ctx.beginPath();
ctx.arc(avatarX + avatarR, avatarY + avatarR, avatarR, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#FFF';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = `bold ${18 * s}px "Roboto", Arial, sans-serif`;
const initial = (videoTitle.charAt(0) || 'V').toUpperCase();
ctx.fillText(initial, avatarX + avatarR, avatarY + avatarR + 1 * s);
// Video Title
ctx.fillStyle = '#FFF';
ctx.font = `${24 * s}px "Roboto", "Segoe UI", Arial, sans-serif`;
ctx.textAlign = 'left';
ctx.shadowColor = 'rgba(0,0,0,0.8)';
ctx.shadowBlur = 5 * s;
ctx.shadowOffsetY = 1 * s;
// Clip the title so it does not overlap top-right icons
ctx.save();
ctx.beginPath();
ctx.rect(avatarX + avatarR * 2 + 15 * s, 0, w - (avatarX + avatarR * 2 + 15 * s) - 100 * s, 100 * s);
ctx.clip();
ctx.fillText(videoTitle, avatarX + avatarR * 2 + 15 * s, avatarY + avatarR + 1 * s);
ctx.restore();
ctx.shadowColor = 'transparent'; // Reset shadow
// Top Right Icons (Info & Share)
let trX = w - 25 * s;
// Info (i) Icon
ctx.strokeStyle = '#FFF';
ctx.lineWidth = 1.5 * s;
ctx.beginPath();
ctx.arc(trX, avatarY + avatarR, 9 * s, 0, Math.PI * 2);
ctx.stroke();
ctx.fillStyle = '#FFF';
ctx.textAlign = 'center';
ctx.font = `bold ${11 * s}px Arial`;
ctx.fillText('i', trX, avatarY + avatarR + 1 * s);
trX -= 40 * s;
// Share Icon
ctx.beginPath();
ctx.moveTo(trX - 7 * s, avatarY + avatarR + 5 * s);
ctx.quadraticCurveTo(trX - 8 * s, avatarY + avatarR - 5 * s, trX + 2 * s, avatarY + avatarR - 5 * s);
ctx.lineTo(trX + 2 * s, avatarY + avatarR - 9 * s);
ctx.lineTo(trX + 10 * s, avatarY + avatarR - 2 * s);
ctx.lineTo(trX + 2 * s, avatarY + avatarR + 5 * s);
ctx.lineTo(trX + 2 * s, avatarY + avatarR + 1 * s);
ctx.quadraticCurveTo(trX - 2 * s, avatarY + avatarR + 1 * s, trX - 7 * s, avatarY + avatarR + 5 * s);
ctx.fill();
// --- 2. Central Red Play Button ---
const btnW = 90 * s;
const btnH = 64 * s;
const btnX = w / 2 - btnW / 2;
const btnY = h / 2 - btnH / 2;
const btnRadius = 16 * s;
ctx.shadowColor = 'rgba(0,0,0,0.5)';
ctx.shadowBlur = 10 * s;
ctx.shadowOffsetY = 2 * s;
ctx.fillStyle = '#FF0000';
drawRoundRect(ctx, btnX, btnY, btnW, btnH, btnRadius);
ctx.fill();
ctx.shadowColor = 'transparent';
// Inner White Triangle
ctx.fillStyle = '#FFF';
ctx.beginPath();
const triW = 24 * s;
const triH = 28 * s;
// Shift slightly to the right to look visually centered
const triX = w / 2 - triW / 2 + 4 * s;
const triY = h / 2 - triH / 2;
ctx.moveTo(triX, triY);
ctx.lineTo(triX + triW, triY + triH / 2);
ctx.lineTo(triX, triY + triH);
ctx.closePath();
ctx.fill();
// --- 3. Bottom Gradient and Controls ---
const ctrlH = 55 * s;
const gradBottom = ctx.createLinearGradient(0, h - ctrlH - 50 * s, 0, h);
gradBottom.addColorStop(0, 'rgba(0,0,0,0)');
gradBottom.addColorStop(1, 'rgba(0,0,0,0.85)');
ctx.fillStyle = gradBottom;
ctx.fillRect(0, h - ctrlH - 50 * s, w, ctrlH + 50 * s);
// Timeline Progress Bar
const padX = 15 * s;
const progY = h - ctrlH;
const progW = w - padX * 2;
const progH = 4 * s;
// Background track
ctx.fillStyle = 'rgba(255,255,255,0.3)';
ctx.fillRect(padX, progY, progW, progH);
// Buffered track
ctx.fillStyle = 'rgba(255,255,255,0.5)';
ctx.fillRect(padX, progY, progW * 0.5, progH);
// Played red track
ctx.fillStyle = '#FF0000';
ctx.fillRect(padX, progY, progW * 0.3, progH);
// Scrub thumb indicator
ctx.beginPath();
ctx.arc(padX + progW * 0.3, progY + progH / 2, 6 * s, 0, Math.PI * 2);
ctx.fill();
// --- Bottom Controls ---
const iconY = h - ctrlH / 2;
// Left Controls: Play, Next, Volume, Time
let currentX = padX + 5 * s;
// Small Play Icon
ctx.fillStyle = '#FFF';
ctx.beginPath();
const playS = 7 * s;
ctx.moveTo(currentX - playS, iconY - playS);
ctx.lineTo(currentX + playS * 1.2, iconY);
ctx.lineTo(currentX - playS, iconY + playS);
ctx.closePath();
ctx.fill();
currentX += 30 * s;
// Next Track
ctx.beginPath();
ctx.moveTo(currentX - 5 * s, iconY - 5 * s);
ctx.lineTo(currentX + 4 * s, iconY);
ctx.lineTo(currentX - 5 * s, iconY + 5 * s);
ctx.closePath();
ctx.fill();
ctx.fillRect(currentX + 5 * s, iconY - 5 * s, 2 * s, 10 * s);
currentX += 30 * s;
// Volume
ctx.beginPath();
const spkW = 4 * s;
const spkH = 4 * s;
ctx.moveTo(currentX - 6 * s, iconY - spkH);
ctx.lineTo(currentX - 1 * s, iconY - spkH);
ctx.lineTo(currentX + 5 * s, iconY - spkH * 2.2);
ctx.lineTo(currentX + 5 * s, iconY + spkH * 2.2);
ctx.lineTo(currentX - 1 * s, iconY + spkH);
ctx.lineTo(currentX - 6 * s, iconY + spkH);
ctx.closePath();
ctx.fill();
ctx.lineWidth = 1.5 * s;
ctx.strokeStyle = '#FFF';
ctx.beginPath();
ctx.arc(currentX + 3 * s, iconY, 6 * s, -Math.PI / 3, Math.PI / 3);
ctx.stroke();
ctx.beginPath();
ctx.arc(currentX + 3 * s, iconY, 10 * s, -Math.PI / 4, Math.PI / 4);
ctx.stroke();
currentX += 35 * s;
// Time Indicator
ctx.fillStyle = '#FFF';
ctx.font = `${13 * s}px "Roboto", "Segoe UI", Arial, sans-serif`;
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
ctx.fillText(`1:23 / ${timestamp}`, currentX, iconY + 1 * s);
// Right Controls: Fullscreen, Theater, Miniplayer, Settings, CC
let rightX = w - padX - 8 * s;
// Fullscreen
ctx.strokeStyle = '#FFF';
ctx.lineWidth = 2 * s;
ctx.beginPath();
const fsSize = 6 * s;
ctx.moveTo(rightX + fsSize - 4 * s, iconY - fsSize);
ctx.lineTo(rightX + fsSize, iconY - fsSize);
ctx.lineTo(rightX + fsSize, iconY - fsSize + 4 * s);
ctx.moveTo(rightX + fsSize, iconY + fsSize - 4 * s);
ctx.lineTo(rightX + fsSize, iconY + fsSize);
ctx.lineTo(rightX + fsSize - 4 * s, iconY + fsSize);
ctx.moveTo(rightX - fsSize + 4 * s, iconY + fsSize);
ctx.lineTo(rightX - fsSize, iconY + fsSize);
ctx.lineTo(rightX - fsSize, iconY + fsSize - 4 * s);
ctx.moveTo(rightX - fsSize, iconY - fsSize + 4 * s);
ctx.lineTo(rightX - fsSize, iconY - fsSize);
ctx.lineTo(rightX - fsSize + 4 * s, iconY - fsSize);
ctx.stroke();
rightX -= 32 * s;
// Theater Mode
const thW = 18 * s;
const thH = 12 * s;
ctx.strokeRect(rightX - thW / 2, iconY - thH / 2, thW, thH);
rightX -= 32 * s;
// Miniplayer (Picture-in-picture)
ctx.strokeRect(rightX - thW / 2, iconY - thH / 2, thW, thH);
ctx.fillStyle = '#FFF';
ctx.fillRect(rightX, iconY + 1 * s, thW / 2 - 2 * s, thH / 2 - 2 * s);
rightX -= 32 * s;
// Settings Gear
const gearX = rightX;
ctx.beginPath();
for (let i = 0; i < 8; i++) {
const angle = i * Math.PI / 4;
const a1 = angle - 0.15;
const a2 = angle + 0.15;
const r1 = 4.5 * s;
const r2 = 7 * s;
ctx.lineTo(gearX + Math.cos(a1) * r1, iconY + Math.sin(a1) * r1);
ctx.lineTo(gearX + Math.cos(a1) * r2, iconY + Math.sin(a1) * r2);
ctx.lineTo(gearX + Math.cos(a2) * r2, iconY + Math.sin(a2) * r2);
ctx.lineTo(gearX + Math.cos(a2) * r1, iconY + Math.sin(a2) * r1);
}
ctx.closePath();
ctx.arc(gearX, iconY, 2.5 * s, 0, Math.PI * 2, true); // Inner ring (reverse direction for cut-out)
ctx.fillStyle = '#FFF';
ctx.fill();
rightX -= 32 * s;
// Subtitles (CC)
ctx.strokeStyle = '#FFF';
ctx.lineWidth = 1.5 * s;
drawRoundRect(ctx, rightX - 10 * s, iconY - 6.5 * s, 20 * s, 13 * s, 2.5 * s);
ctx.stroke();
ctx.fillStyle = '#FFF';
ctx.font = `bold ${7.5 * s}px Arial`;
ctx.textAlign = 'center';
ctx.fillText('CC', rightX, iconY + 0.5 * s);
return canvas;
}
Apply Changes