You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, title = 'Bon Appรฉtit!', borderColor = '#F5DEB3', titleFont = 'Lobster', titleColor = '#FFFFFF') {
/**
* Dynamically loads a Google Font by creating and appending a <link> tag to the document head.
* It also waits for the font to be ready for use in a canvas context.
* @param {string} fontFamily - The name of the Google Font to load.
*/
const loadGoogleFont = async (fontFamily) => {
const fontId = `google-font-${fontFamily.replace(/\s/g, '-')}`;
// Avoid adding the same font link multiple times
if (document.getElementById(fontId)) {
// Wait for the font to be usable in canvas
await document.fonts.load(`1em "${fontFamily}"`);
return;
}
const url = `https://fonts.googleapis.com/css2?family=${fontFamily.replace(' ', '+')}:wght@400;700&display=swap`;
const link = document.createElement('link');
link.id = fontId;
link.rel = 'stylesheet';
link.href = url;
const loadPromise = new Promise((resolve, reject) => {
link.onload = resolve;
link.onerror = reject;
});
document.head.appendChild(link);
await loadPromise;
// Ensure the font is ready for the canvas context after the stylesheet has loaded
await document.fonts.load(`1em "${fontFamily}"`);
};
// A collection of food-related emojis to decorate the border
const foodEmojis = ['๐', '๐', '๐', '๐ญ', '๐ฟ', '๐ฅ', '๐ฅ', '๐ง', '๐ฅ', '๐', '๐ฅ', '๐ฅจ', '๐ฅฏ', '๐ง', '๐ฅ', '๐ฅ', '๐ฅช', '๐ฎ', '๐ฏ', '๐ฑ', '๐', '๐', '๐', '๐', '๐ฃ', '๐ฆ', '๐ฅง', '๐ง', '๐ฐ', '๐', '๐ฎ', '๐ญ', '๐ฌ', '๐ซ', '๐ฉ', '๐ช', 'โ', '๐ท', '๐ป', '๐', '๐', '๐', '๐', '๐', '๐ฅฆ', '๐ฅ', '๐ฝ', '๐ถ๏ธ'];
const getRandomEmoji = () => foodEmojis[Math.floor(Math.random() * foodEmojis.length)];
// 1. Load the required font for the title
try {
await loadGoogleFont(titleFont);
} catch (e) {
console.error(`Could not load Google Font "${titleFont}". Using a fallback font.`, e);
titleFont = 'serif'; // Use a web-safe fallback font
}
// 2. Set up canvas dimensions
const padding = 60; // The width of the decorative border
const canvas = document.createElement('canvas');
canvas.width = originalImg.naturalWidth + padding * 2;
canvas.height = originalImg.naturalHeight + padding * 2;
const ctx = canvas.getContext('2d');
// 3. Draw the background border and the main image
ctx.fillStyle = borderColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(originalImg, padding, padding, originalImg.naturalWidth, originalImg.naturalHeight);
// 4. Draw the decorative emoji border
ctx.font = `${padding * 0.6}px sans-serif`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// Draw corners first
ctx.fillText(getRandomEmoji(), padding / 2, padding / 2);
ctx.fillText(getRandomEmoji(), canvas.width - padding / 2, padding / 2);
ctx.fillText(getRandomEmoji(), padding / 2, canvas.height - padding / 2);
ctx.fillText(getRandomEmoji(), canvas.width - padding / 2, canvas.height - padding / 2);
// Draw top and bottom borders with evenly spaced emojis
const horizontalIcons = Math.floor(originalImg.naturalWidth / padding);
if(horizontalIcons > 0) {
const horizontalSpacing = originalImg.naturalWidth / horizontalIcons;
for (let i = 0; i < horizontalIcons; i++) {
const x = padding + i * horizontalSpacing + horizontalSpacing / 2;
ctx.fillText(getRandomEmoji(), x, padding / 2);
ctx.fillText(getRandomEmoji(), x, canvas.height - padding / 2);
}
}
// Draw left and right borders with evenly spaced emojis
const verticalIcons = Math.floor(originalImg.naturalHeight / padding);
if (verticalIcons > 0) {
const verticalSpacing = originalImg.naturalHeight / verticalIcons;
for (let i = 0; i < verticalIcons; i++) {
const y = padding + i * verticalSpacing + verticalSpacing / 2;
ctx.fillText(getRandomEmoji(), padding / 2, y);
ctx.fillText(getRandomEmoji(), canvas.width - padding / 2, y);
}
}
// 5. Draw the title over the image if one is provided
if (title && title.trim() !== '') {
// Calculate a dynamic font size based on the image width
const fontSize = Math.max(24, Math.floor(originalImg.naturalWidth / 18));
ctx.font = `bold ${fontSize}px "${titleFont}", serif`;
// Calculate position for the title at the bottom of the image
const textX = canvas.width / 2;
const textY = canvas.height - padding - fontSize * 0.8;
const textMetrics = ctx.measureText(title);
const bgPadding = fontSize * 0.3;
const bgWidth = textMetrics.width + bgPadding * 2;
const bgHeight = fontSize + bgPadding;
const bgX = textX - bgWidth / 2;
const bgY = textY - bgHeight / 2 - bgPadding / 4;
// Draw a semi-transparent, rounded background for better readability
ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
ctx.beginPath();
if (ctx.roundRect) {
ctx.roundRect(bgX, bgY, bgWidth, bgHeight, 15);
} else {
// Fallback for older browsers that don't support roundRect
ctx.rect(bgX, bgY, bgWidth, bgHeight);
}
ctx.fill();
// Draw the title text
ctx.fillStyle = titleColor;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(title, textX, textY);
}
// 6. Return the final canvas element
return canvas;
}
Apply Changes