You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg,
headline = "BREAKING NEWS",
subhead = "MAJOR EVENT UNFOLDS AS WORLD WATCHES LIVE",
ticker = "UPDATE: NEW DETAILS EMERGING... TRUTH REVEALED...",
liveText = "LIVE",
themeColor = "#cc0000",
textColor = "#000000"
) {
const canvas = document.createElement('canvas');
canvas.width = originalImg.width;
canvas.height = originalImg.height;
const ctx = canvas.getContext('2d');
// Draw original image as background
ctx.drawImage(originalImg, 0, 0);
const W = canvas.width;
const H = canvas.height;
// Dimensions
const tickerH = Math.max(H * 0.07, 24);
const mainH = Math.max(H * 0.12, 40);
const tickerY = H - tickerH;
const mainY = tickerY - mainH;
// Slant calculations (slants forwards / )
const splitX_top = W * 0.30;
const splitX_bot = W * 0.33;
const redBox = [
{x: 0, y: mainY},
{x: splitX_top, y: mainY},
{x: splitX_bot, y: mainY + mainH},
{x: 0, y: mainY + mainH}
];
const whiteBox = [
{x: splitX_top, y: mainY},
{x: W, y: mainY},
{x: W, y: mainY + mainH},
{x: splitX_bot, y: mainY + mainH}
];
// Helper to draw polygons
function drawPoly(points, fillStyle) {
ctx.fillStyle = fillStyle;
ctx.beginPath();
ctx.moveTo(points[0].x, points[0].y);
for(let i = 1; i < points.length; i++) {
ctx.lineTo(points[i].x, points[i].y);
}
ctx.closePath();
ctx.fill();
}
// Main lighting gradient for TV glossy effect
const glossyOverlay = ctx.createLinearGradient(0, mainY, 0, mainY + mainH);
glossyOverlay.addColorStop(0, 'rgba(255, 255, 255, 0.4)');
glossyOverlay.addColorStop(0.4, 'rgba(255, 255, 255, 0.05)');
glossyOverlay.addColorStop(0.5, 'rgba(0, 0, 0, 0.05)');
glossyOverlay.addColorStop(1, 'rgba(0, 0, 0, 0.3)');
// 1. Draw Main Banner (Headline & Subhead blocks)
// Left Block (Red/Theme)
drawPoly(redBox, themeColor);
drawPoly(redBox, glossyOverlay);
// Right Block (White/Solid)
drawPoly(whiteBox, '#f5f5f5');
drawPoly(whiteBox, glossyOverlay);
// Top Accent Border Line over the white box
ctx.fillStyle = themeColor;
ctx.fillRect(splitX_top, mainY - H * 0.005, W - splitX_top, H * 0.005);
// 2. Draw Bottom Ticker
ctx.fillStyle = '#111111';
ctx.fillRect(0, tickerY, W, tickerH);
// Time Box (Bottom Right)
const timeBoxW = W * 0.12;
const timeX = W - timeBoxW;
ctx.fillStyle = themeColor;
ctx.fillRect(timeX, tickerY, timeBoxW, tickerH);
// Helper for shrink-to-fit text
function writeShrinkText(text, x, y, width, height, color, align = 'left', maxFontSize = 100) {
let fontSize = maxFontSize;
ctx.fillStyle = color;
ctx.textAlign = align;
ctx.textBaseline = 'middle';
while (fontSize > 4) {
ctx.font = `900 ${fontSize}px Impact, "Arial Black", Arial, sans-serif`;
const metrics = ctx.measureText(text);
if (metrics.width <= width && fontSize <= height) break;
fontSize--;
}
let finalX = x;
if (align === 'center') finalX = x + width / 2;
else if (align === 'right') finalX = x + width;
// Shadow for bright texts for readability
if (color === '#ffffff' || color === 'white') {
ctx.shadowColor = 'rgba(0,0,0,0.6)';
ctx.shadowBlur = 4;
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
}
ctx.fillText(text, finalX, y + height / 2 + (fontSize * 0.05));
ctx.shadowColor = 'transparent'; // Reset
}
// Draw Headline Text (Red Box)
const redTextMaxWidth = splitX_top * 0.85;
const redTextX = (splitX_top / 2); // Center of top width
writeShrinkText(headline, redTextX - (redTextMaxWidth/2), mainY, redTextMaxWidth, mainH * 0.7, '#ffffff', 'center', mainH * 0.65);
// Draw Subhead Text (White Box)
const whiteTextStartX = splitX_bot + (W * 0.02);
const whiteTextMaxWidth = W - whiteTextStartX - (W * 0.02);
writeShrinkText(subhead, whiteTextStartX, mainY, whiteTextMaxWidth, mainH * 0.7, textColor, 'left', mainH * 0.6);
// Draw Clock (Time Box)
const now = new Date();
const timeStr = now.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' });
writeShrinkText(timeStr, timeX, tickerY, timeBoxW, tickerH * 0.8, '#ffffff', 'center', tickerH * 0.6);
// Draw Ticker Text (Using clipping for authentic scroll cut-off)
const tickerTextW = timeX - (W * 0.02);
ctx.save();
ctx.beginPath();
ctx.rect(W * 0.02, tickerY, tickerTextW, tickerH);
ctx.clip(); // Ensure long texts don't run into the clock
ctx.fillStyle = '#ffcc00'; // Classic ticker yellow
ctx.font = `bold ${tickerH * 0.55}px Arial, sans-serif`;
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
ctx.fillText(" " + ticker, W * 0.02, tickerY + tickerH / 2 + tickerH * 0.05);
ctx.restore();
// 3. Draw LIVE Indicator (Top Left Bug)
if (liveText && liveText.trim() !== '') {
const liveH = Math.max(H * 0.045, 25);
const fontSz = liveH * 0.6;
ctx.font = `900 ${fontSz}px Arial, sans-serif`;
const liveTextW = ctx.measureText(liveText).width;
const r = liveH * 0.2; // Blinking circle radius
const liveW = liveTextW + (r * 2) + (liveH * 0.6) + (liveH * 0.4);
const liveX = W * 0.04;
const liveY = H * 0.04;
// Banner Base
ctx.fillStyle = themeColor;
ctx.fillRect(liveX, liveY, liveW, liveH);
// Gloss
const liveGloss = ctx.createLinearGradient(0, liveY, 0, liveY + liveH);
liveGloss.addColorStop(0, 'rgba(255,255,255,0.4)');
liveGloss.addColorStop(1, 'rgba(0,0,0,0.2)');
ctx.fillStyle = liveGloss;
ctx.fillRect(liveX, liveY, liveW, liveH);
// Recording Dot White Circle
const cx = liveX + (liveH * 0.5);
const cy = liveY + (liveH / 2);
ctx.beginPath();
ctx.arc(cx, cy, r, 0, Math.PI * 2);
ctx.fillStyle = '#ffffff';
ctx.shadowColor = 'rgba(0,0,0,0.5)';
ctx.shadowBlur = 3;
ctx.fill();
ctx.shadowColor = 'transparent';
// liveText
const textStartX = cx + r + (liveH * 0.25);
writeShrinkText(liveText, textStartX, liveY, liveW, liveH * 0.8, '#ffffff', 'left', fontSz);
}
return canvas;
}
Apply Changes