You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg,
titleText = "CARNIVAL FUN!",
detailsText = "GAMES - RIDES - FOOD - PRIZES",
taglineText = "COME ONE, COME ALL!",
bannerText = "GRAND EVENT!",
primaryBgColor = "#D90429", // Strong Red
secondaryBgColor = "#FFFFFF", // White for stripes
accentColor = "#FFD700", // Gold/Yellow
textColor = "#FFFFFF", // White for main title/tagline
bannerTextColor = "#000000", // Black for text on banner
fontFamily = "Bangers" // Default font to load dynamically
) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const posterWidth = 600;
const posterHeight = 800;
canvas.width = posterWidth;
canvas.height = posterHeight;
// 1. Font handling
let currentFont = fontFamily; // This might change to a fallback font
const dynamicFonts = {
"Bangers": "https://fonts.gstatic.com/s/bangers/v24/FeVQS0BTqb0h60ACL5k.woff2",
"Lobster": "https://fonts.gstatic.com/s/lobster/v30/neILzCirqoswsqX9zoKmMw.woff2",
"Luckiest Guy": "https://fonts.gstatic.com/s/luckiestguy/v18/_gP_1RrxsjcxVyin9l9n_j2hTd52.woff2",
"Limelight": "https://fonts.gstatic.com/s/limelight/v21/XLYkIZL7aopIFB2 திருச்சிUr-v9-.woff2" // Note: Truncated font name for Limelight due to non-ASCII
};
// Correcting font name for Limelight or similar
if (fontFamily === "Limelight") dynamicFonts["Limelight"] = "https://fonts.gstatic.com/s/limelight/v21/XLYkIZL7aopIFB2_oGg.woff2";
if (dynamicFonts[fontFamily]) {
if (document.fonts) {
try {
if (!document.fonts.check(`1em "${fontFamily}"`)) {
const fontFace = new FontFace(fontFamily, `url(${dynamicFonts[fontFamily]}) format('woff2')`);
await fontFace.load();
document.fonts.add(fontFace);
await document.fonts.ready;
if (!document.fonts.check(`1em "${fontFamily}"`)) {
console.warn(`Font "${fontFamily}" loaded but check() returns false. Attempting to use.`);
}
console.log(`Font "${fontFamily}" loaded dynamically.`);
} else {
console.log(`Font "${fontFamily}" is already available.`);
}
currentFont = fontFamily;
} catch (e) {
console.error(`Failed to load font "${fontFamily}":`, e);
currentFont = "Arial, sans-serif";
}
} else {
console.warn("document.fonts API not supported. Using fallback font for dynamic request.");
currentFont = "Arial, sans-serif";
}
} else {
console.log(`Using provided font "${fontFamily}" assuming it's available or loaded externally.`);
currentFont = fontFamily; // Assume it's a system font or loaded elsewhere
}
// 2. Background (Stripes)
ctx.save();
const stripeWidth = 50;
for (let i = 0; i * stripeWidth < posterWidth; i++) {
ctx.fillStyle = (i % 2 === 0) ? primaryBgColor : secondaryBgColor;
ctx.fillRect(i * stripeWidth, 0, stripeWidth, posterHeight);
}
ctx.restore();
// 3. Decorative Border
ctx.save();
const outerBorderWidth = 20;
ctx.strokeStyle = accentColor;
ctx.lineWidth = outerBorderWidth;
ctx.strokeRect(
outerBorderWidth / 2,
outerBorderWidth / 2,
posterWidth - outerBorderWidth,
posterHeight - outerBorderWidth
);
const innerBorderVisualGap = 5;
const innerBorderLineWidth = 5;
const innerBorderRectX = outerBorderWidth + innerBorderVisualGap;
const innerBorderRectY = outerBorderWidth + innerBorderVisualGap;
const innerBorderRectW = posterWidth - 2 * (outerBorderWidth + innerBorderVisualGap);
const innerBorderRectH = posterHeight - 2 * (outerBorderWidth + innerBorderVisualGap);
ctx.strokeStyle = primaryBgColor;
ctx.lineWidth = innerBorderLineWidth;
ctx.strokeRect(innerBorderRectX, innerBorderRectY, innerBorderRectW, innerBorderRectH);
ctx.restore();
// Helper for drawing text
function drawStyledText(text, x, y, fontSize, font, fillStyle, shadowSettings, strokeSettings) {
ctx.save();
ctx.font = `bold ${fontSize}px "${font}"`;
ctx.fillStyle = fillStyle;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
if (shadowSettings && shadowSettings.color && shadowSettings.color !== 'transparent') {
ctx.shadowColor = shadowSettings.color;
ctx.shadowOffsetX = shadowSettings.offsetX || 0;
ctx.shadowOffsetY = shadowSettings.offsetY || 0;
ctx.shadowBlur = shadowSettings.blur || 0;
}
if (strokeSettings && strokeSettings.color && strokeSettings.color !== 'transparent' && strokeSettings.width > 0) {
ctx.strokeStyle = strokeSettings.color;
ctx.lineWidth = strokeSettings.width;
ctx.strokeText(text, x, y);
}
ctx.fillText(text, x, y);
ctx.restore();
}
// 4. Title Text
const titleY = 90; // Adjusted Y for better spacing
drawStyledText(titleText, posterWidth / 2, titleY, 70, currentFont, textColor,
{ color: 'rgba(0,0,0,0.7)', offsetX: 4, offsetY: 4, blur: 6 },
{ color: 'black', width: 4 }
);
// 5. Image Placement
const imgFramePadding = 10;
// Available space for image container (frame + image) considering main borders
const mainBorderTotalWidth = outerBorderWidth + innerBorderVisualGap + innerBorderLineWidth;
const imgAreaMargin = mainBorderTotalWidth + 10; // 10px margin from inner border
const imgContainerX = imgAreaMargin;
const imgContainerY = titleY + 70; // Space below title
const imgContainerWidth = posterWidth - 2 * imgAreaMargin;
const imgContainerHeight = 300;
let dWidth, dHeight, dx, dy;
const imgAspectRatio = originalImg.width / originalImg.height;
const availableImgContentWidth = imgContainerWidth - 2 * imgFramePadding;
const availableImgContentHeight = imgContainerHeight - 2 * imgFramePadding;
const contentAspectRatio = availableImgContentWidth / availableImgContentHeight;
if (imgAspectRatio > contentAspectRatio) {
dWidth = availableImgContentWidth;
dHeight = dWidth / imgAspectRatio;
} else {
dHeight = availableImgContentHeight;
dWidth = dHeight * imgAspectRatio;
}
dx = imgContainerX + imgFramePadding + (availableImgContentWidth - dWidth) / 2;
dy = imgContainerY + imgFramePadding + (availableImgContentHeight - dHeight) / 2;
ctx.save();
ctx.fillStyle = secondaryBgColor;
ctx.fillRect(imgContainerX, imgContainerY, imgContainerWidth, imgContainerHeight);
ctx.strokeStyle = accentColor;
ctx.lineWidth = 5;
ctx.strokeRect(imgContainerX, imgContainerY, imgContainerWidth, imgContainerHeight);
ctx.drawImage(originalImg, dx, dy, dWidth, dHeight);
ctx.restore();
// 6. Details Text
const detailsY = imgContainerY + imgContainerHeight + 45; // Adjusted Y
drawStyledText(detailsText, posterWidth / 2, detailsY, 30, currentFont, accentColor,
{ color: 'rgba(0,0,0,0.5)', offsetX: 2, offsetY: 2, blur: 3 },
{ color: primaryBgColor, width: 2 }
);
// 7. Banner with text
const bannerY = detailsY + 60;
const bannerHeight = 60;
const bannerWidth = posterWidth * 0.85;
const bannerRectX = (posterWidth - bannerWidth) / 2;
ctx.save();
ctx.fillStyle = accentColor;
ctx.fillRect(bannerRectX, bannerY - bannerHeight / 2, bannerWidth, bannerHeight);
ctx.font = `bold 35px "${currentFont}"`;
ctx.fillStyle = bannerTextColor;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.shadowColor = 'rgba(255,255,255,0.4)';
ctx.shadowOffsetX = 1;
ctx.shadowOffsetY = 1;
ctx.shadowBlur = 1;
if (bannerTextColor !== primaryBgColor && bannerTextColor !== 'transparent') {
ctx.strokeStyle = 'rgba(0,0,0,0.15)';
ctx.lineWidth = 1;
if (ctx.lineWidth > 0) ctx.strokeText(bannerText, posterWidth / 2, bannerY);
}
ctx.fillText(bannerText, posterWidth / 2, bannerY);
ctx.restore();
// 8. Tagline Text
const taglineY = bannerY + bannerHeight / 2 + 50; // Adjusted Y
drawStyledText(taglineText, posterWidth / 2, taglineY, 40, currentFont, textColor,
{ color: 'rgba(0,0,0,0.7)', offsetX: 3, offsetY: 3, blur: 5 },
{ color: 'black', width: 3 }
);
// 9. Decorative stars
function drawStar(cx, cy, spikes, outerRadius, innerRadius, starFillColor) {
ctx.save();
let rot = Math.PI / 2 * 3;
let x = cx;
let y = cy;
const step = Math.PI / spikes;
ctx.beginPath();
ctx.moveTo(cx, cy - outerRadius);
for (let i = 0; i < spikes; i++) {
x = cx + Math.cos(rot) * outerRadius;
y = cy + Math.sin(rot) * outerRadius;
ctx.lineTo(x, y);
rot += step;
x = cx + Math.cos(rot) * innerRadius;
y = cy + Math.sin(rot) * innerRadius;
ctx.lineTo(x, y);
rot += step;
}
ctx.lineTo(cx, cy - outerRadius);
ctx.closePath();
ctx.fillStyle = starFillColor;
ctx.fill();
ctx.restore();
}
const starPositions = [
{ x: 60, y: posterHeight - 60, outerR: 20, innerR: 10 },
{ x: posterWidth - 60, y: posterHeight - 60, outerR: 20, innerR: 10 },
{ x: posterWidth / 2, y: posterHeight - 45, outerR: 25, innerR: 12 },
{ x: 70, y: titleY + 170, outerR: 15, innerR: 7 },
{ x: posterWidth - 70, y: titleY + 170, outerR: 15, innerR: 7 },
{ x: 45, y: 45, outerR: 12, innerR: 5},
{ x: posterWidth - 45, y: 45, outerR: 12, innerR: 5}
];
starPositions.forEach(s => drawStar(s.x, s.y, 5, s.outerR, s.innerR, accentColor));
return canvas;
}
Apply Changes