You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, tvColor = "#795548", tvStyle = "retro", backgroundColor = "transparent") {
const canvas = document.createElement('canvas');
const width = 512;
const height = 512;
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
// Helper function to draw rounded rectangles
function drawRoundRect(ctx, x, y, w, h, r) {
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.lineTo(x + w - r, y);
ctx.arcTo(x + w, y, x + w, y + h, r);
ctx.lineTo(x + w, y + h - r);
ctx.arcTo(x + w, y + h, x, y + h, r);
ctx.lineTo(x + r, y + h);
ctx.arcTo(x, y + h, x, y, r);
ctx.lineTo(x, y + r);
ctx.arcTo(x, y, x + w, y, r);
ctx.closePath();
}
// 1. Draw Background
if (backgroundColor !== "transparent") {
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, width, height);
}
const isModern = tvStyle.toLowerCase() === 'modern';
// 2. Back Elements (Stand or Legs & Antenna)
if (isModern) {
// Modern TV Stand
ctx.fillStyle = '#2c3e50';
// Neck
ctx.fillRect(231, 396, 50, 30);
// Base
drawRoundRect(ctx, 156, 426, 200, 15, 7);
ctx.fill();
} else {
// Retro TV Legs
ctx.lineWidth = 14;
ctx.lineCap = 'round';
ctx.strokeStyle = '#34495e';
ctx.beginPath();
ctx.moveTo(96, 386);
ctx.lineTo(66, 466);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(416, 386);
ctx.lineTo(446, 466);
ctx.stroke();
// Retro TV Antenna
ctx.lineWidth = 6;
ctx.strokeStyle = '#7f8c8d';
ctx.beginPath();
ctx.moveTo(256, 126);
ctx.lineTo(150, 46);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(256, 126);
ctx.lineTo(362, 46);
ctx.stroke();
// Antenna Base Connection
ctx.beginPath();
ctx.arc(256, 120, 20, 0, Math.PI * 2);
ctx.fillStyle = '#34495e';
ctx.fill();
// Antenna Tips
ctx.beginPath();
ctx.arc(150, 46, 8, 0, Math.PI * 2);
ctx.fillStyle = '#bdc3c7';
ctx.fill();
ctx.beginPath();
ctx.arc(362, 46, 8, 0, Math.PI * 2);
ctx.fillStyle = '#bdc3c7';
ctx.fill();
}
// 3. TV Main Body Construction
const tvX = 36, tvY = 116, tvW = 440, tvH = 280, tvR = isModern ? 12 : 24;
// Base TV Block
drawRoundRect(ctx, tvX, tvY, tvW, tvH, tvR);
ctx.fillStyle = tvColor;
ctx.fill();
// Inner shadow for depth
ctx.lineWidth = 4;
ctx.strokeStyle = 'rgba(0,0,0,0.3)';
ctx.stroke();
// Inner Highlight Frame
ctx.beginPath();
drawRoundRect(ctx, tvX + 2, tvY + 2, tvW - 4, tvH - 4, tvR - 2);
ctx.strokeStyle = 'rgba(255,255,255,0.15)';
ctx.lineWidth = 2;
ctx.stroke();
// 4. Calculate Inner Screen Dimensions
let bezelX, bezelY, bezelW, bezelH, bezelR;
let scrX, scrY, scrW, scrH, scrR;
if (isModern) {
bezelW = 430; bezelH = 270;
bezelX = tvX + (tvW - bezelW) / 2;
bezelY = tvY + (tvH - bezelH) / 2;
bezelR = 8;
scrW = 422; scrH = 262;
scrX = bezelX + (bezelW - scrW) / 2;
scrY = bezelY + (bezelH - scrH) / 2;
scrR = 6;
} else {
bezelX = 56; bezelY = 136; bezelW = 320; bezelH = 240; bezelR = 20;
scrX = 66; scrY = 146; scrW = 300; scrH = 220; scrR = 15;
}
// 5. Draw Bezel (Dark area surrounding the glass screen)
drawRoundRect(ctx, bezelX, bezelY, bezelW, bezelH, bezelR);
ctx.fillStyle = '#111';
ctx.fill();
// 6. Draw Content Screen (Original Image properly cropped & fitted)
ctx.save();
drawRoundRect(ctx, scrX, scrY, scrW, scrH, scrR);
ctx.clip();
// Provide a dark base background inside the screen for transparent PNGs
ctx.fillStyle = '#0a0a0a';
ctx.fillRect(scrX, scrY, scrW, scrH);
// Apply Object-fit cover logic to maintain aspect ratio without distortion
const imgRatio = originalImg.width / originalImg.height;
const screenRatio = scrW / scrH;
let drawW, drawH, drawX, drawY;
if (imgRatio > screenRatio) {
drawH = scrH;
drawW = drawH * imgRatio;
drawX = scrX - (drawW - scrW) / 2;
drawY = scrY;
} else {
drawW = scrW;
drawH = drawW / imgRatio;
drawX = scrX;
drawY = scrY - (drawH - scrH) / 2;
}
ctx.drawImage(originalImg, drawX, drawY, drawW, drawH);
// Add Glass Glare Overlay
const gradient = ctx.createLinearGradient(scrX, scrY, scrX + scrW, scrY + scrH);
if (!isModern) {
// Retro CRT glass curvature shine
gradient.addColorStop(0, 'rgba(255, 255, 255, 0.25)');
gradient.addColorStop(0.4, 'rgba(255, 255, 255, 0.05)');
gradient.addColorStop(0.41, 'rgba(255, 255, 255, 0)');
gradient.addColorStop(1, 'rgba(0, 0, 0, 0.4)');
} else {
// Modern uniform soft matte finish
gradient.addColorStop(0, 'rgba(255, 255, 255, 0.1)');
gradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.02)');
gradient.addColorStop(0.51, 'rgba(255, 255, 255, 0)');
gradient.addColorStop(1, 'rgba(0, 0, 0, 0.15)');
}
ctx.fillStyle = gradient;
ctx.fill();
// Frame shadow directly on glass for bulky TVs
if (!isModern) {
ctx.strokeStyle = 'rgba(0,0,0,0.6)';
ctx.lineWidth = 10;
ctx.stroke();
}
ctx.restore();
// 7. Render Front Interface (Knobs, Grills, or LED)
if (!isModern) {
// Control Panel Base
const panelX = 396, panelY = 136, panelW = 60, panelH = 240, panelR = 15;
drawRoundRect(ctx, panelX, panelY, panelW, panelH, panelR);
ctx.fillStyle = 'rgba(0,0,0,0.15)';
ctx.fill();
ctx.lineWidth = 1.5;
ctx.strokeStyle = 'rgba(255,255,255,0.1)';
ctx.stroke();
// Mechanical Knobs Factory
function drawKnob(kx, ky) {
// Shadow Underneath
ctx.beginPath();
ctx.arc(kx, ky, 22, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(0,0,0,0.5)';
ctx.fill();
// Structure Base
ctx.beginPath();
ctx.arc(kx, ky - 2, 20, 0, Math.PI * 2);
ctx.fillStyle = '#222';
ctx.fill();
// Silver Metallic Top
ctx.beginPath();
ctx.arc(kx, ky - 3, 16, 0, Math.PI * 2);
const grad = ctx.createLinearGradient(kx - 16, ky - 20, kx + 16, ky + 16);
grad.addColorStop(0, '#fff');
grad.addColorStop(0.5, '#ccc');
grad.addColorStop(1, '#666');
ctx.fillStyle = grad;
ctx.fill();
// Grip / Set Point Indicator Line
ctx.beginPath();
ctx.moveTo(kx, ky - 3);
ctx.lineTo(kx + 10, ky - 11);
ctx.strokeStyle = '#333';
ctx.lineWidth = 4;
ctx.lineCap = 'round';
ctx.stroke();
}
drawKnob(426, 171);
drawKnob(426, 231);
// Speaker Grills Area
ctx.strokeStyle = 'rgba(0,0,0,0.6)';
ctx.lineWidth = 4;
ctx.lineCap = 'round';
for (let i = 0; i < 6; i++) {
const gy = 280 + i * 14;
// Indent Dark Area
ctx.beginPath();
ctx.moveTo(406, gy);
ctx.lineTo(446, gy);
ctx.stroke();
// Below Edge Highlight
ctx.beginPath();
ctx.moveTo(406, gy + 2);
ctx.lineTo(446, gy + 2);
ctx.strokeStyle = 'rgba(255,255,255,0.1)';
ctx.lineWidth = 1.5;
ctx.stroke();
ctx.strokeStyle = 'rgba(0,0,0,0.6)'; // restore styling
}
} else {
// Subtle active power LED for Modern mode
ctx.beginPath();
ctx.arc(460, 386, 3, 0, Math.PI * 2);
ctx.fillStyle = '#2ecc71';
ctx.fill();
ctx.shadowColor = '#2ecc71';
ctx.shadowBlur = 6;
ctx.fill();
ctx.shadowBlur = 0; // reset
}
return canvas;
}
Apply Changes