You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(
originalImg,
showTitle = "YOUR GRAND MUSICAL",
tagline = "An Unforgettable Theatrical Event!",
presenterText = "YOUR THEATRE COMPANY PRESENTS",
starringText = "Starring: Famous Actor\nAcclaimed Actress",
creditsText1 = "Music by COMPOSER NAME\nLyrics by LYRICIST NAME\nBook by WRITER NAME",
creditsText2 = "Directed by DIRECTOR NAME\nChoreography by CHOREOGRAPHER NAME",
venueInfoText = "GRAND THEATRE - OPENS SOON!",
bottomLineText = "Visit website.com for tickets and more information.",
textColor = "#FFFFFF",
accentColor = "#FFD700",
backgroundColor = "#000000",
titleFontParam = "Ultra",
bodyFontParam = "Roboto Condensed"
) {
const _global = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
async function _loadWebFont(fontFamilyName) {
const knownFonts = {
'Ultra': { family: 'Ultra', url: 'https://fonts.gstatic.com/s/ultra/v19/zOLy4prXmrtY-tT6yL6xDaY.woff2' },
'Roboto Condensed': { family: 'Roboto Condensed', url: 'https://fonts.gstatic.com/s/robotocondensed/v25/ieVl2ZhZI2eCN5jzbjEETS9weq8-19-7DQk6YvNkeg.woff2' },
'Bebas Neue': { family: 'Bebas Neue', url: 'https://fonts.gstatic.com/s/bebasneue/v9/JTUSjIg69CK48gW7PXoo9Wlhyw.woff2' },
'Oswald': { family: 'Oswald', url: 'https://fonts.gstatic.com/s/oswald/v49/TK3_WkUHHAIjg75cFRf3bXL8LICs1_FvsUtiZSSUhiCXAA.woff2' }
};
const fontData = knownFonts[fontFamilyName];
if (fontData && _global.FontFace && _global.document && _global.document.fonts) {
let fontAvailable = false;
try { // document.fonts check might throw SecurityError in sandboxed iframes
fontAvailable = Array.from(_global.document.fonts).some(f => f.family === fontData.family);
} catch(e) {/*ignore*/}
if (fontAvailable) {
return true;
}
const fontFace = new _global.FontFace(fontData.family, `url(${fontData.url})`);
try {
await fontFace.load();
_global.document.fonts.add(fontFace);
return true;
} catch (e) {
console.error(`Error loading font ${fontData.family}:`, e);
return false;
}
}
return false;
}
function _drawTextWithNewlines(ctx, text, x, startY, lineHeight, fontStyle, fontSize, fontFamily, color, textAlign = 'center') {
ctx.font = `${fontStyle} ${fontSize}px ${fontFamily}`;
ctx.fillStyle = color;
ctx.textAlign = textAlign;
const lines = String(text).split('\n'); // Ensure text is a string, then split
let currentY = startY;
lines.forEach((line, index) => {
ctx.fillText(line.trim(), x, currentY);
if (index < lines.length - 1) {
currentY += lineHeight;
}
});
return currentY;
}
const fontPromises = [];
if (titleFontParam && typeof titleFontParam === 'string') fontPromises.push(_loadWebFont(titleFontParam));
if (bodyFontParam && typeof bodyFontParam === 'string') fontPromises.push(_loadWebFont(bodyFontParam));
if (fontPromises.length > 0) {
await Promise.all(fontPromises);
}
const cssTitleFontFamily = `${titleFontParam ? "'" + titleFontParam + "', " : ""}Impact, 'Arial Black', sans-serif`;
const cssBodyFontFamily = `${bodyFontParam ? "'" + bodyFontParam + "', " : ""}'Arial Condensed', Arial, sans-serif`;
const canvas = _global.document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 700;
canvas.height = 1050;
// 1. Background
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 2. Decorative Borders
ctx.strokeStyle = accentColor;
ctx.lineWidth = 10;
ctx.strokeRect(5, 5, canvas.width - 10, canvas.height - 10);
ctx.lineWidth = 2;
ctx.strokeRect(15, 15, canvas.width - 30, canvas.height - 30);
let currentY = 0;
// 3. Presenter Text
currentY = _drawTextWithNewlines(ctx, presenterText.toUpperCase(), canvas.width / 2, 60, 22, "", 18, cssBodyFontFamily, textColor);
// 4. Show Title
currentY = _drawTextWithNewlines(ctx, showTitle.toUpperCase(), canvas.width / 2, currentY + 60, 75, "bold", 70, cssTitleFontFamily, accentColor);
// 5. Tagline
currentY = _drawTextWithNewlines(ctx, tagline, canvas.width / 2, currentY + 35, 28, "italic", 24, cssBodyFontFamily, textColor);
// 6. Main Image
const imgAreaY = currentY + 30;
const imgAreaHeight = 380;
const imgAreaWidth = canvas.width - 100;
const imgAreaX = (canvas.width - imgAreaWidth) / 2;
if (originalImg && originalImg.width > 0 && originalImg.height > 0) {
const imgAspectRatio = originalImg.width / originalImg.height;
let drawWidth = imgAreaWidth;
let drawHeight = drawWidth / imgAspectRatio;
if (drawHeight > imgAreaHeight) {
drawHeight = imgAreaHeight;
drawWidth = drawHeight * imgAspectRatio;
}
if (drawWidth > imgAreaWidth) { // Recalc if previous adjustment made it too wide (e.g. very panoramic image)
drawWidth = imgAreaWidth;
drawHeight = drawWidth / imgAspectRatio;
}
const offsetX = (imgAreaWidth - drawWidth) / 2;
const offsetY = (imgAreaHeight - drawHeight) / 2;
ctx.drawImage(originalImg, imgAreaX + offsetX, imgAreaY + offsetY, drawWidth, drawHeight);
ctx.strokeStyle = accentColor;
ctx.lineWidth = 2;
ctx.strokeRect(imgAreaX + offsetX - 3, imgAreaY + offsetY - 3, drawWidth + 6, drawHeight + 6);
}
currentY = imgAreaY + imgAreaHeight;
// 7. Starring Text
currentY = _drawTextWithNewlines(ctx, starringText, canvas.width / 2, currentY + 40, 25, "", 20, cssBodyFontFamily, textColor);
// 8. Credits Text 1
currentY = _drawTextWithNewlines(ctx, creditsText1, canvas.width / 2, currentY + 30, 18, "", 14, cssBodyFontFamily, textColor);
// 9. Credits Text 2
currentY = _drawTextWithNewlines(ctx, creditsText2, canvas.width / 2, currentY + 15, 18, "", 14, cssBodyFontFamily, textColor);
// 10. Venue Info Text (from bottom up)
_drawTextWithNewlines(ctx, venueInfoText.toUpperCase(), canvas.width / 2, canvas.height - 70, 22, "bold", 18, cssBodyFontFamily, accentColor);
// 11. Bottom Line Text (from bottom up)
_drawTextWithNewlines(ctx, bottomLineText, canvas.width / 2, canvas.height - 35, 15, "", 12, cssBodyFontFamily, textColor);
return canvas;
}
Apply Changes