Please bookmark this page to avoid losing your image tool!

Image Recipe And Ingredient Viewer

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
async function processImage(
    originalImg, 
    title = 'Classic Homemade Pizza', 
    ingredients = '- 2 ½ cups all-purpose flour\n- 1 teaspoon sugar\n- 1 teaspoon instant yeast\n- 1 cup warm water\n- 2 tablespoons olive oil\n\n- ½ cup pizza sauce\n- 2 cups shredded mozzarella cheese\n- Your favorite toppings', 
    recipeSteps = '1. Make the dough: In a large bowl, whisk together flour, sugar, yeast, and salt. Add warm water and olive oil, and stir until a shaggy dough forms. Knead for 5 minutes on a floured surface until smooth. Place in a greased bowl, cover, and let rise for 1 hour.\n\n2. Prepare the pizza: Preheat oven to 475°F (245°C). Punch down the dough and stretch it into a 12-inch circle.\n\n3. Add toppings: Spread pizza sauce evenly over the dough. Sprinkle with mozzarella cheese and add your desired toppings.\n\n4. Bake: Bake for 12-15 minutes, or until the crust is golden brown and the cheese is bubbly. Slice and enjoy!'
) {

    /**
     * Dynamically loads the required Google Fonts for the recipe card.
     * It ensures the font stylesheet is added to the document only once.
     */
    const loadFonts = async () => {
        const FONT_FAMILIES = "Lato:wght@400;700&family=Playfair+Display:wght@700";
        const FONT_URL = `https://fonts.googleapis.com/css2?family=${FONT_FAMILIES.replace(/ /g, '+')}&display=swap`;
        
        if (!document.querySelector(`link[href="${FONT_URL}"]`)) {
            const link = document.createElement('link');
            link.href = FONT_URL;
            link.rel = 'stylesheet';
            document.head.appendChild(link);
            // The document.fonts.ready promise resolves when fonts are loaded and ready.
            await document.fonts.ready;
        }
    };

    /**
     * A helper function to wrap text on a canvas. It can operate in two modes:
     * - 'draw' mode (doDraw = true): Renders text onto the canvas.
     * - 'measure' mode (doDraw = false): Calculates the total height of the text block without drawing.
     * @returns {number} The total height occupied by the text block.
     */
    const wrapText = (context, text, x, y, maxWidth, lineHeight, doDraw = true) => {
        const lines = text.split('\n');
        let totalHeight = 0;
        let currentY = y;

        lines.forEach(line => {
            // Treat empty lines as paragraph spacing
            if (line.trim() === '') {
                const paragraphSpacing = lineHeight * 0.5;
                if (doDraw) currentY += paragraphSpacing;
                totalHeight += paragraphSpacing;
                return;
            }

            let words = line.split(' ');
            let lineBuffer = '';
            for (let i = 0; i < words.length; i++) {
                let testBuffer = lineBuffer + words[i] + ' ';
                let metrics = context.measureText(testBuffer.trim());

                if (metrics.width > maxWidth && i > 0) {
                    if (doDraw) context.fillText(lineBuffer.trim(), x, currentY);
                    lineBuffer = words[i] + ' ';
                    currentY += lineHeight;
                    totalHeight += lineHeight;
                } else {
                    lineBuffer = testBuffer;
                }
            }
            if (doDraw) context.fillText(lineBuffer.trim(), x, currentY);
            currentY += lineHeight;
            totalHeight += lineHeight;
        });
        
        return totalHeight;
    };

    // --- Main Logic ---

    await loadFonts();

    // 1. Define layout constants and styles
    const CANVAS_WIDTH = 800;
    const PADDING = 50;
    const TEXT_AREA_WIDTH = CANVAS_WIDTH - 2 * PADDING;
    
    const BACKGROUND_COLOR = '#fdfaf2'; // A warm, parchment-like background
    const TEXT_COLOR = '#3d3d3d';

    const TITLE_FONT = '700 48px "Playfair Display"';
    const TITLE_LINE_HEIGHT = 60;
    const HEADING_FONT = '700 24px "Lato"';
    const HEADING_HEIGHT = 30; // Approx height for a single line heading
    const BODY_FONT = '400 16px "Lato"';
    const BODY_LINE_HEIGHT = 26;

    // 2. Calculate scaled image height to maintain aspect ratio
    const imgHeight = originalImg.height * (CANVAS_WIDTH / originalImg.width);

    // 3. Pre-calculate the total height needed for the canvas
    const tempCanvas = document.createElement('canvas');
    const tempCtx = tempCanvas.getContext('2d');
    
    let totalTextHeight = PADDING; // Start with top padding

    tempCtx.font = TITLE_FONT;
    totalTextHeight += wrapText(tempCtx, title, 0, 0, TEXT_AREA_WIDTH, TITLE_LINE_HEIGHT, false);
    totalTextHeight += PADDING / 2;

    tempCtx.font = HEADING_FONT;
    totalTextHeight += HEADING_HEIGHT; // For "Ingredients"
    totalTextHeight += PADDING / 2;
    tempCtx.font = BODY_FONT;
    totalTextHeight += wrapText(tempCtx, ingredients, 0, 0, TEXT_AREA_WIDTH, BODY_LINE_HEIGHT, false);
    totalTextHeight += PADDING;

    tempCtx.font = HEADING_FONT;
    totalTextHeight += HEADING_HEIGHT; // For "Recipe"
    totalTextHeight += PADDING / 2;
    tempCtx.font = BODY_FONT;
    totalTextHeight += wrapText(tempCtx, recipeSteps, 0, 0, TEXT_AREA_WIDTH, BODY_LINE_HEIGHT, false);
    totalTextHeight += PADDING; // Final bottom padding

    // 4. Create the final canvas with the calculated dimensions
    const totalCanvasHeight = imgHeight + totalTextHeight;
    const canvas = document.createElement('canvas');
    canvas.width = CANVAS_WIDTH;
    canvas.height = totalCanvasHeight;
    const ctx = canvas.getContext('2d');

    // 5. Draw all elements onto the canvas
    ctx.fillStyle = BACKGROUND_COLOR;
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(originalImg, 0, 0, CANVAS_WIDTH, imgHeight);

    let currentY = imgHeight + PADDING;
    ctx.fillStyle = TEXT_COLOR;

    // Draw Title (centered)
    ctx.font = TITLE_FONT;
    ctx.textAlign = 'center';
    const titleActualHeight = wrapText(ctx, title, CANVAS_WIDTH / 2, currentY, TEXT_AREA_WIDTH, TITLE_LINE_HEIGHT, true);
    currentY += titleActualHeight + PADDING / 2;
    
    // Draw Ingredients (left-aligned)
    ctx.textAlign = 'left';
    ctx.font = HEADING_FONT;
    ctx.fillText('Ingredients', PADDING, currentY);
    currentY += HEADING_HEIGHT + PADDING / 2;
    ctx.font = BODY_FONT;
    const ingredientsActualHeight = wrapText(ctx, ingredients, PADDING, currentY, TEXT_AREA_WIDTH, BODY_LINE_HEIGHT, true);
    currentY += ingredientsActualHeight + PADDING;

    // Draw Recipe Steps (left-aligned)
    ctx.font = HEADING_FONT;
    ctx.fillText('Recipe', PADDING, currentY);
    currentY += HEADING_HEIGHT + PADDING / 2;
    ctx.font = BODY_FONT;
    wrapText(ctx, recipeSteps, PADDING, currentY, TEXT_AREA_WIDTH, BODY_LINE_HEIGHT, true);

    return canvas;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Image Recipe And Ingredient Viewer is a tool designed to visually present recipes in a formatted layout that combines an image with the recipe details. Users can upload an image related to the recipe they wish to showcase, and the tool generates a graphical representation that includes the recipe title, a comprehensive list of ingredients, and step-by-step cooking instructions. This tool is ideal for food bloggers, recipe creators, or anyone looking to share culinary creations visually on social media, websites, or digital cookbooks.

Leave a Reply

Your email address will not be published. Required fields are marked *