You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, numberOfVerbs = 10, fontFamily = 'Roboto', fontSize = 24, textColor = '#333333') {
/**
* Dynamically loads a font from Google Fonts if it's not a standard web-safe font.
* This ensures that Cyrillic characters are displayed correctly.
* @param {string} family - The font family name.
* @param {number} size - The font size, needed for the Font Loading API.
* @returns {Promise<string>} The effective font family name (original or fallback).
*/
const loadFont = async (family, size) => {
const webSafeFonts = ['Arial', 'Verdana', 'Helvetica', 'Tahoma', 'Trebuchet MS', 'Times New Roman', 'Georgia', 'Garamond', 'Courier New', 'Brush Script MT'];
// Check if the font is a common web-safe font
if (webSafeFonts.find(f => f.toLowerCase() === family.toLowerCase())) {
return family;
}
// If not web-safe, assume it's a Google Font and try to load it.
const fontId = `google-font-stylesheet-${family.replace(/\s+/g, '-')}`;
try {
if (!document.getElementById(fontId)) {
const fontName = family.replace(/\s+/g, '+');
const url = `https://fonts.googleapis.com/css2?family=${fontName}:wght@400;700&display=swap`;
const link = document.createElement('link');
link.id = fontId;
link.href = url;
link.rel = 'stylesheet';
document.head.appendChild(link);
}
// Use the Font Loading API to wait until the font is ready.
await document.fonts.load(`${size}px ${family}`);
return family;
} catch (e) {
console.warn(`Could not load Google Font "${family}". Falling back to 'Arial'.`, e);
return 'Arial'; // Fallback to a reliable web-safe font
}
};
// Ensure the specified font is loaded before we start measuring text.
const effectiveFontFamily = await loadFont(fontFamily, fontSize);
// A predefined list of evocative Russian verbs ("Глаголы").
const verbs = [
'Смотреть', 'Думать', 'Чувствовать', 'Бежать', 'Лететь',
'Создавать', 'Разрушать', 'Помнить', 'Забывать', 'Расти',
'Падать', 'Начинать', 'Заканчивать', 'Любить', 'Ждать',
'Надеяться', 'Мечтать', 'Открывать', 'Закрывать', 'Искать',
'Находить', 'Менять', 'Строить', 'Дышать', 'Жить',
'Петь', 'Танцевать', 'Говорить', 'Молчать', 'Смеяться',
'Плакать', 'Улыбаться', 'Играть', 'Прятать', 'Светить',
'Слушать', 'Держать', 'Касаться', 'Верить', 'Терять'
];
// Helper function to get N random unique items from an array.
const getRandomItems = (arr, n) => {
const shuffled = [...arr].sort(() => 0.5 - Math.random());
return shuffled.slice(0, Math.min(n, arr.length));
};
const selectedVerbs = getRandomItems(verbs, numberOfVerbs);
// Create a canvas to draw the final result.
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// --- Layout Calculations ---
// 1. Calculate scaled image dimensions to fit within a max boundary.
let imgWidth = originalImg.naturalWidth;
let imgHeight = originalImg.naturalHeight;
const maxDim = 500;
if (imgWidth > maxDim || imgHeight > maxDim) {
if (imgWidth > imgHeight) {
imgHeight = (maxDim / imgWidth) * imgHeight;
imgWidth = maxDim;
} else {
imgWidth = (maxDim / imgHeight) * imgWidth;
imgHeight = maxDim;
}
}
// 2. Calculate dimensions required for the text block.
ctx.font = `${fontSize}px ${effectiveFontFamily}`;
const textMetrics = selectedVerbs.map(verb => ctx.measureText(verb));
const maxTextWidth = Math.max(...textMetrics.map(m => m.width));
const lineHeight = fontSize * 1.5;
const textBlockHeight = lineHeight * selectedVerbs.length;
// 3. Determine final canvas dimensions with padding and spacing.
const padding = 25;
const gap = 25;
canvas.width = padding + imgWidth + gap + maxTextWidth + padding;
canvas.height = padding + Math.max(imgHeight, textBlockHeight) + padding;
// --- Drawing Operations ---
// 1. Draw a background.
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 2. Draw the image. It's vertically centered relative to the overall height.
const contentHeight = Math.max(imgHeight, textBlockHeight);
const imageY = padding + (contentHeight - imgHeight) / 2;
ctx.drawImage(originalImg, padding, imageY, imgWidth, imgHeight);
// 3. Draw the verbs. The entire text block is vertically centered.
ctx.fillStyle = textColor;
ctx.font = `${fontSize}px ${effectiveFontFamily}`;
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
const textStartX = padding + imgWidth + gap;
const textStartY = padding + (contentHeight - textBlockHeight) / 2;
selectedVerbs.forEach((verb, index) => {
const y = textStartY + (index * lineHeight) + (lineHeight / 2);
ctx.fillText(verb, textStartX, y);
});
return canvas;
}
Apply Changes