You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, title = "Classic Pancakes", ingredients = "1 1/2 cups all-purpose flour\n3 1/2 teaspoons baking powder\n1 teaspoon salt\n1 tablespoon white sugar\n1 1/4 cups milk\n1 egg\n3 tablespoons butter, melted", instructions = "1. In a large bowl, sift together the flour, baking powder, salt and sugar.\n2. Make a well in the center and pour in the milk, egg and melted butter; mix until smooth.\n3. Heat a lightly oiled griddle or frying pan over medium high heat.\n4. Pour or scoop the batter onto the griddle, using approximately 1/4 cup for each pancake.\n5. Brown on both sides and serve hot.", fontFamily = "Georgia, serif", fontSize = 16, textColor = "#FFFFFF", backgroundColor = "rgba(0, 0, 0, 0.6)", padding = 25, position = "topLeft") {
// 1. Create canvas and draw the original image
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = originalImg.naturalWidth;
canvas.height = originalImg.naturalHeight;
ctx.drawImage(originalImg, 0, 0);
// 2. Define text styles and parse multi-line text
const titleSize = Math.round(fontSize * 1.5);
const headerSize = Math.round(fontSize * 1.1);
const bodySize = fontSize;
const lineSpacing = fontSize * 0.5;
const ingredientLines = ingredients.split('\n').filter(line => line.trim() !== '');
const instructionLines = instructions.split('\n').filter(line => line.trim() !== '');
const ingredientsHeader = "INGREDIENTS";
const instructionsHeader = "INSTRUCTIONS";
// 3. Measure the required dimensions for the recipe box without drawing
let contentWidth = 0;
let contentHeightTracker = padding; // Start with top padding
// Measure Title
ctx.font = `bold ${titleSize}px ${fontFamily}`;
contentWidth = Math.max(contentWidth, ctx.measureText(title).width);
contentHeightTracker += titleSize + lineSpacing * 2;
// Measure Ingredients Header
ctx.font = `bold ${headerSize}px ${fontFamily}`;
contentWidth = Math.max(contentWidth, ctx.measureText(ingredientsHeader).width);
contentHeightTracker += headerSize + lineSpacing;
// Measure Ingredient Lines
ctx.font = `${bodySize}px ${fontFamily}`;
ingredientLines.forEach(line => {
contentWidth = Math.max(contentWidth, ctx.measureText(line).width);
contentHeightTracker += bodySize + lineSpacing;
});
contentHeightTracker += lineSpacing; // Extra space between sections
// Measure Instructions Header
ctx.font = `bold ${headerSize}px ${fontFamily}`;
contentWidth = Math.max(contentWidth, ctx.measureText(instructionsHeader).width);
contentHeightTracker += headerSize + lineSpacing;
// Measure Instruction Lines
ctx.font = `${bodySize}px ${fontFamily}`;
instructionLines.forEach(line => {
contentWidth = Math.max(contentWidth, ctx.measureText(line).width);
contentHeightTracker += bodySize + lineSpacing;
});
// Final box dimensions
const totalBoxWidth = contentWidth + padding * 2;
// contentHeightTracker includes all text heights and spacings. The last line added an extra lineSpacing.
// We replace that last spacing with the bottom padding.
const totalBoxHeight = contentHeightTracker - lineSpacing + padding;
// 4. Calculate the top-left (x, y) coordinates for the box based on position
let boxX, boxY;
const margin = Number(padding); // Use padding as margin from edge
switch (position) {
case 'topRight':
boxX = canvas.width - totalBoxWidth - margin;
boxY = margin;
break;
case 'bottomLeft':
boxX = margin;
boxY = canvas.height - totalBoxHeight - margin;
break;
case 'bottomRight':
boxX = canvas.width - totalBoxWidth - margin;
boxY = canvas.height - totalBoxHeight - margin;
break;
case 'center':
boxX = (canvas.width - totalBoxWidth) / 2;
boxY = (canvas.height - totalBoxHeight) / 2;
break;
case 'topLeft':
default:
boxX = margin;
boxY = margin;
break;
}
// Clamp box position to be within the canvas
boxX = Math.max(0, boxX);
boxY = Math.max(0, boxY);
// 5. Draw the background box
ctx.fillStyle = backgroundColor;
ctx.fillRect(boxX, boxY, totalBoxWidth, Math.min(totalBoxHeight, canvas.height - boxY));
// 6. Draw the text
ctx.fillStyle = textColor;
ctx.textBaseline = 'top';
let currentY = boxY + padding;
const textX = boxX + padding;
// Draw Title
ctx.font = `bold ${titleSize}px ${fontFamily}`;
ctx.fillText(title, textX, currentY);
currentY += titleSize + lineSpacing * 2;
// Draw Ingredients
ctx.font = `bold ${headerSize}px ${fontFamily}`;
ctx.fillText(ingredientsHeader, textX, currentY);
currentY += headerSize + lineSpacing;
ctx.font = `${bodySize}px ${fontFamily}`;
ingredientLines.forEach(line => {
ctx.fillText(line, textX, currentY);
currentY += bodySize + lineSpacing;
});
currentY += lineSpacing; // Extra space
// Draw Instructions
ctx.font = `bold ${headerSize}px ${fontFamily}`;
ctx.fillText(instructionsHeader, textX, currentY);
currentY += headerSize + lineSpacing;
ctx.font = `${bodySize}px ${fontFamily}`;
instructionLines.forEach(line => {
ctx.fillText(line, textX, currentY);
currentY += bodySize + lineSpacing;
});
return canvas;
}
Apply Changes