You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, tvColor = '#d28c46', panelColor = '#222222', enableCRT = 1) {
const 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();
};
const W = originalImg.width;
const H = originalImg.height;
// Scale down if image is too large to keep canvas manageable visually
const maxDim = 700;
let scale = 1;
if (W > maxDim || H > maxDim) {
scale = maxDim / Math.max(W, H);
}
const sw = W * scale;
const sh = H * scale;
// Dynamic metrics based on screen size
const margin = Math.max(sw * 0.08, 20);
const panelW = Math.max(sw * 0.25, 60);
const tvW = sw + panelW + margin * 3;
const tvH = sh + margin * 2;
const antH = Math.max(sh * 0.25, 40);
const legH = Math.max(sh * 0.15, 30);
const padCanvas = 40;
const canvas = document.createElement('canvas');
canvas.width = tvW + padCanvas * 2;
canvas.height = tvH + antH + legH + padCanvas * 2;
const ctx = canvas.getContext('2d');
const startX = padCanvas;
const startY = padCanvas + antH;
// --- Draw TV Legs ---
ctx.fillStyle = tvColor;
ctx.strokeStyle = '#333';
ctx.lineWidth = 3;
const legW = margin * 0.8;
// Left Leg
ctx.beginPath();
const llX = startX + tvW * 0.15;
const llY = startY + tvH - 10;
ctx.moveTo(llX - legW/2, llY);
ctx.lineTo(llX + legW/2, llY);
ctx.lineTo(llX + legW, llY + legH);
ctx.lineTo(llX - legW*0.2, llY + legH);
ctx.closePath();
ctx.fill(); ctx.stroke();
// Right Leg
ctx.beginPath();
const rlX = startX + tvW * 0.85;
ctx.moveTo(rlX - legW/2, llY);
ctx.lineTo(rlX + legW/2, llY);
ctx.lineTo(rlX + legW*0.2, llY + legH);
ctx.lineTo(rlX - legW, llY + legH);
ctx.closePath();
ctx.fill(); ctx.stroke();
// --- Draw Antenna ---
const antBaseX = startX + tvW / 2;
ctx.lineWidth = 4;
ctx.strokeStyle = '#999';
ctx.beginPath();
ctx.moveTo(antBaseX, startY);
ctx.lineTo(antBaseX - tvW * 0.25, startY - antH);
ctx.moveTo(antBaseX, startY);
ctx.lineTo(antBaseX + tvW * 0.25, startY - antH);
ctx.stroke();
// Antenna Tips
ctx.fillStyle = '#555';
ctx.beginPath();
ctx.arc(antBaseX - tvW * 0.25, startY - antH, 6, 0, Math.PI * 2);
ctx.fill();
ctx.beginPath();
ctx.arc(antBaseX + tvW * 0.25, startY - antH, 6, 0, Math.PI * 2);
ctx.fill();
// Antenna Base
ctx.fillStyle = '#222';
drawRoundRect(ctx, antBaseX - 30, startY - 8, 60, 16, 4);
ctx.fill();
// --- Draw TV Body ---
ctx.shadowColor = 'rgba(0,0,0,0.4)';
ctx.shadowBlur = 20;
ctx.shadowOffsetX = 5;
ctx.shadowOffsetY = 10;
ctx.fillStyle = tvColor;
drawRoundRect(ctx, startX, startY, tvW, tvH, margin * 0.5);
ctx.fill();
// Reset shadow
ctx.shadowColor = 'transparent';
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
// Body Outline
ctx.lineWidth = 4;
ctx.strokeStyle = '#222';
ctx.stroke();
// --- Draw Hardware Panel ---
const pX = startX + margin * 2 + sw;
const pY = startY + margin;
ctx.fillStyle = panelColor;
drawRoundRect(ctx, pX, pY, panelW, sh, margin * 0.2);
ctx.fill();
// Panel Dials / Knobs
const dialR = Math.min(panelW * 0.35, sh * 0.15);
const dialX = pX + panelW / 2;
let dialY1 = pY + margin + dialR;
let dialY2 = dialY1 + dialR * 2.5;
const drawDial = (x, y) => {
// Outer shiny ring
ctx.fillStyle = '#6a6a6a';
ctx.beginPath(); ctx.arc(x, y, dialR, 0, Math.PI * 2); ctx.fill();
// Inner knob base
ctx.fillStyle = '#e0e0e0';
ctx.beginPath(); ctx.arc(x, y, dialR * 0.75, 0, Math.PI * 2); ctx.fill();
// Knob shadow/depth rim
ctx.strokeStyle = '#999'; ctx.lineWidth = 2; ctx.stroke();
// Positional notch mark
ctx.strokeStyle = '#222';
ctx.lineWidth = 4;
ctx.lineCap = 'round';
ctx.beginPath();
ctx.moveTo(x, y);
const angle = -Math.PI / 4 + (Math.random() * Math.PI); // Randomize dial twist
ctx.lineTo(x + Math.cos(angle) * dialR * 0.6, y + Math.sin(angle) * dialR * 0.6);
ctx.stroke();
};
drawDial(dialX, dialY1);
drawDial(dialX, dialY2);
// Speaker Grill
const grillY = dialY2 + dialR * 1.5;
const grillH = sh - (grillY - pY) - margin;
if (grillH > 15) {
ctx.fillStyle = '#111';
const slots = Math.max(3, Math.floor(grillH / 14));
const slotSpacing = grillH / slots;
for (let i = 0; i < slots; i++) {
drawRoundRect(ctx, pX + panelW * 0.2, grillY + i * slotSpacing, panelW * 0.6, slotSpacing * 0.4, 3);
ctx.fill();
}
}
// --- Draw Screen CRT ---
const screenX = startX + margin;
const screenY = startY + margin;
// Background Cavity (Dark border behind the physical screen)
ctx.fillStyle = '#0a0a0a';
drawRoundRect(ctx, screenX - 5, screenY - 5, sw + 10, sh + 10, margin * 0.4);
ctx.fill();
// Render image with clipping mask
ctx.save();
drawRoundRect(ctx, screenX, screenY, sw, sh, margin * 0.3);
ctx.clip();
// Fallback black base inside screen
ctx.fillStyle = '#000';
ctx.fillRect(screenX, screenY, sw, sh);
// Inject Image
ctx.drawImage(originalImg, screenX, screenY, sw, sh);
// Overlay CRT Effects (if requested)
if (Number(enableCRT) > 0) {
// Interlaced Scanlines
ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
for (let i = 0; i < sh; i += 3) {
ctx.fillRect(screenX, screenY + i, sw, 1);
}
// Curved aesthetic screen glare
ctx.fillStyle = 'rgba(255, 255, 255, 0.06)';
ctx.beginPath();
ctx.moveTo(screenX, screenY);
ctx.lineTo(screenX + sw, screenY);
ctx.lineTo(screenX + sw, screenY + sh * 0.4);
ctx.quadraticCurveTo(screenX + sw * 0.5, screenY + sh * 0.8, screenX, screenY + sh * 0.4);
ctx.fill();
// Screen spherical depth vignette
const radialVignette = ctx.createRadialGradient(
screenX + sw/2, screenY + sh/2, Math.min(sw, sh) * 0.4,
screenX + sw/2, screenY + sh/2, Math.max(sw, sh) * 0.75
);
radialVignette.addColorStop(0, 'rgba(0,0,0,0)');
radialVignette.addColorStop(1, 'rgba(0,0,0,0.85)');
ctx.fillStyle = radialVignette;
ctx.fillRect(screenX, screenY, sw, sh);
}
ctx.restore();
// Inner Tube Rim highlighting
ctx.strokeStyle = '#333';
ctx.lineWidth = 2;
drawRoundRect(ctx, screenX, screenY, sw, sh, margin * 0.3);
ctx.stroke();
return canvas;
}
Apply Changes