You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, cardTitle = "Рецепт Малосольных Огурчиков", themeColor = "#2c5921", bgColor = "#fffaf0") {
// Basic settings for layout
const width = 800;
const maxImgHeight = 450;
let scaleImg = width / originalImg.width;
let imgHeight = originalImg.height * scaleImg;
if (imgHeight > maxImgHeight) {
imgHeight = maxImgHeight;
}
// Use a dummy canvas just for accurately measuring text wrapping heights
const dummyCanvas = document.createElement('canvas');
const dCtx = dummyCanvas.getContext('2d');
// Helper function to handle text wrapping and measuring
function measureAndDrawText(ctxToDraw, text, x, y, maxWidth, lineHeight, font, color, doDraw = false) {
if (doDraw) {
ctxToDraw.font = font;
ctxToDraw.fillStyle = color;
ctxToDraw.textAlign = "left";
ctxToDraw.textBaseline = "top";
} else {
dCtx.font = font;
}
const words = text.split(' ');
let line = '';
let currentY = y;
for(let i = 0; i < words.length; i++) {
const testLine = line + words[i] + ' ';
const metrics = doDraw ? ctxToDraw.measureText(testLine) : dCtx.measureText(testLine);
if (metrics.width > maxWidth && i > 0) {
if (doDraw) ctxToDraw.fillText(line, x, currentY);
line = words[i] + ' ';
currentY += lineHeight;
} else {
line = testLine;
}
}
if (doDraw) ctxToDraw.fillText(line, x, currentY);
return currentY + lineHeight;
}
// Calculating vertical bounds dynamically based on text
let cursorY = imgHeight + 40;
cursorY += 45; // Title height space
cursorY += 60; // Subtitle height space
cursorY += 45; // Column headers height space
const contentStartY = cursorY;
// Hardcoded Recipe Data for Lightly Salted Pickles
const ingredients = [
"• Огурцы: 1 кг (небольшие, крепкие)",
"• Вода: 1 литр",
"• Соль: 2 ст. ложки (без горки)",
"• Чеснок: 4-5 зубчиков",
"• Укроп: 1 пучок (зонтики и стебли)",
"• Листья: вишни, смородины, хрена (по желанию)"
];
let ingY = contentStartY;
const col1X = 50;
const col1W = 280;
for (let item of ingredients) {
ingY = measureAndDrawText(dCtx, item, col1X, ingY, col1W, 28, "18px sans-serif", "#000", false);
ingY += 10;
}
const instructions = [
"1. Тщательно вымойте огурцы. Для усиления хруста замочите их в ледяной воде на 1-2 часа.",
"2. Отрежьте кончики огурцов с обеих сторон для лучшего и быстрого просола.",
"3. На дно чистой банки (или кастрюли) уложите половину всей зелени и нарезанный пластинами чеснок.",
"4. Плотно уложите огурцы: нижние ряды вертикально, а верхние, по возможности, горизонтально.",
"5. Сверху накройте огурцы оставшимся чесноком, веточками укропа и листьями.",
"6. Приготовьте рассол: в 1 литре воды растворите 2 столовые ложки соли. Залейте огурцы так, чтобы вода закрыла их.",
" (Подсказка: Горячая вода ускорит процесс до 24 часов. Холодная вода сохранит максимальный хруст, но готовность займет 2-3 дня).",
"7. Оставьте банку под закрытой крышкой при комнатной температуре. Как только огурчики готовы, уберите на хранение в холодильник!"
];
let instY = contentStartY;
const col2X = 360;
const col2W = 390;
for (let item of instructions) {
instY = measureAndDrawText(dCtx, item, col2X, instY, col2W, 28, "18px sans-serif", "#000", false);
instY += 12;
}
const finalY = Math.max(ingY, instY) + 60; // Add lower padding for the footer
// CREATE AND RENDER ACTUAL CANVAS
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = finalY + 40;
const ctx = canvas.getContext('2d');
// Draw solid background
ctx.fillStyle = bgColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw the Image (styled as Object-Fit: Cover)
const scale = Math.max(width / originalImg.width, imgHeight / originalImg.height);
const drawW = originalImg.width * scale;
const drawH = originalImg.height * scale;
const drawX = (width - drawW) / 2;
const drawY = (imgHeight - drawH) / 2;
ctx.save();
ctx.beginPath();
ctx.rect(0, 0, width, imgHeight);
ctx.clip(); // Mask boundaries
ctx.drawImage(originalImg, drawX, drawY, drawW, drawH);
ctx.restore();
// Subtle edge shadow below the image
ctx.fillStyle = "rgba(0,0,0,0.08)";
ctx.fillRect(0, imgHeight, width, 4);
// Draw Title Header
let drawCursorY = imgHeight + 40;
ctx.font = "bold 36px 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif";
ctx.fillStyle = themeColor;
ctx.textAlign = "center";
ctx.textBaseline = "top";
ctx.fillText(cardTitle, width / 2, drawCursorY);
drawCursorY += 45;
// Draw Subtitle
ctx.font = "italic 20px 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif";
ctx.fillStyle = "#555555";
ctx.fillText("Идеальная хрустящая закуска — просто, быстро и безумно вкусно!", width / 2, drawCursorY);
drawCursorY += 60;
// Draw Section Titles
ctx.font = "bold 24px 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif";
ctx.fillStyle = themeColor;
ctx.textAlign = "left";
ctx.fillText("Ингредиенты:", col1X, drawCursorY);
ctx.fillText("Приготовление:", col2X, drawCursorY);
// Draw subtle separation lines
ctx.globalAlpha = 0.2;
ctx.fillRect(col1X, drawCursorY + 35, col1W - 20, 2);
ctx.fillRect(col2X, drawCursorY + 35, col2W - 20, 2);
ctx.globalAlpha = 1.0;
drawCursorY += 55;
// Draw Rendered Column 1 (Ingredients)
let drawIngY = drawCursorY;
for (let item of ingredients) {
drawIngY = measureAndDrawText(ctx, item, col1X, drawIngY, col1W, 28, "18px 'Segoe UI', Tahoma, Geneva, sans-serif", "#333333", true);
drawIngY += 10;
}
// Draw Rendered Column 2 (Instructions)
let drawInstY = drawCursorY;
for (let item of instructions) {
drawInstY = measureAndDrawText(ctx, item, col2X, drawInstY, col2W, 28, "18px 'Segoe UI', Tahoma, Geneva, sans-serif", "#333333", true);
drawInstY += 12;
}
// Draw Ending Footer
ctx.font = "italic bold 22px 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif";
ctx.fillStyle = themeColor;
ctx.textAlign = "center";
ctx.fillText("Приятного аппетита!", width / 2, Math.max(drawIngY, drawInstY) + 30);
return canvas;
}
Apply Changes