Please bookmark this page to avoid losing your image tool!

Image Infographic Creator

(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,
    titleText = "Infographic Title",
    titleColor = "black",
    titleFontSize = 30,
    titleFontFamily = "Arial",
    descriptionText = "Some insightful facts and details about the displayed image. This text can wrap to multiple lines if it's long enough.",
    descriptionColor = "dimgray",
    descriptionFontSize = 16,
    descriptionFontFamily = "Arial",
    backgroundColor = "white",
    padding = 20,
    infographicContentWidth = 600
) {

    // 0. Ensure fonts are loaded (best-effort for non-system fonts)
    try {
        // Quote font family names to handle spaces correctly
        if (titleText.trim() !== "") {
            await document.fonts.load(`${titleFontSize}px "${titleFontFamily}"`);
        }
        if (descriptionText.trim() !== "") {
            await document.fonts.load(`${descriptionFontSize}px "${descriptionFontFamily}"`);
        }
    } catch (err) {
        console.warn(`Font loading issue: ${err}. System fallback fonts will be used.`);
        // Browser will typically use a fallback font. For simplicity, no explicit fallback change here.
    }

    // 1. Handle invalid original image (e.g., not loaded or zero dimensions)
    if (!originalImg || originalImg.width === 0 || originalImg.height === 0) {
        console.error("Original image is invalid or has zero dimensions.");
        const errorCanvas = document.createElement('canvas');
        const placeholderWidth = infographicContentWidth > 0 ? infographicContentWidth : 200;
        const placeholderHeight = 100;
        errorCanvas.width = placeholderWidth + 2 * Math.max(0, padding);
        errorCanvas.height = placeholderHeight + 2 * Math.max(0, padding);
        const errCtx = errorCanvas.getContext('2d');
        
        errCtx.fillStyle = backgroundColor;
        errCtx.fillRect(0, 0, errorCanvas.width, errorCanvas.height);
        
        errCtx.fillStyle = "red";
        errCtx.font = "16px Arial";
        errCtx.textAlign = "center";
        errCtx.textBaseline = "middle";
        errCtx.fillText("Error: Invalid Image Data", errorCanvas.width / 2, errorCanvas.height / 2);
        return errorCanvas;
    }
    
    // Ensure padding and content width are reasonable
    padding = Math.max(0, padding);
    infographicContentWidth = Math.max(10, infographicContentWidth); // Minimum content width


    // 2. Determine image scale to fit infographicContentWidth
    let scaledImgWidth = originalImg.width;
    let scaledImgHeight = originalImg.height;

    if (originalImg.width > infographicContentWidth) {
        const scaleRatio = infographicContentWidth / originalImg.width;
        scaledImgWidth = infographicContentWidth;
        scaledImgHeight = originalImg.height * scaleRatio;
    }
    // If image is narrower than infographicContentWidth, it uses its original width
    // and will be centered within the infographicContentWidth area.

    // Create a temporary canvas to draw the (potentially scaled) image.
    const tempImgCanvas = document.createElement('canvas');
    tempImgCanvas.width = scaledImgWidth;
    tempImgCanvas.height = scaledImgHeight;
    const tempImgCtx = tempImgCanvas.getContext('2d');
    tempImgCtx.drawImage(originalImg, 0, 0, scaledImgWidth, scaledImgHeight);

    // 3. Create final canvas and context
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    // 4. Define text styles and helper for height calculation
    const titleFullFont = `${titleFontSize}px "${titleFontFamily}"`;
    const descriptionFullFont = `${descriptionFontSize}px "${descriptionFontFamily}"`;

    // Helper Function to calculate height of wrapped text
    function calculateWrappedTextHeight(context, text, textFont, maxWidth, lineHeight) {
        text = String(text); // Ensure text is a string
        if (text.trim() === "") return 0;
        
        context.font = textFont;
        const words = text.split(' ');
        let line = '';
        let lines = 0;

        if (words.every(word => word === "")) return 0; // Handles text that is only spaces effectively

        for (let n = 0; n < words.length; n++) {
            const testLine = line + words[n] + ' ';
            const metrics = context.measureText(testLine);
            if (metrics.width > maxWidth && line.trim() !== '') { // Current line + new word is too long, and current line has content
                lines++;
                line = words[n] + ' '; // Start new line with current word
            } else {
                line = testLine; // Word fits, or it's the first word (even if too long by itself)
            }
        }
        if (line.trim() !== '') lines++; // Count any remaining line
        return lines * lineHeight;
    }

    const titleLineHeight = titleFontSize * 1.2; 
    const titleBlockHeight = titleText.trim() === "" ? 0 : calculateWrappedTextHeight(ctx, titleText, titleFullFont, infographicContentWidth, titleLineHeight);

    const descriptionLineHeight = descriptionFontSize * 1.4;
    const descriptionBlockHeight = descriptionText.trim() === "" ? 0 : calculateWrappedTextHeight(ctx, descriptionText, descriptionFullFont, infographicContentWidth, descriptionLineHeight);

    // 5. Calculate Overall Canvas Dimensions
    const canvasFinalWidth = infographicContentWidth + 2 * padding;
    
    let canvasFinalHeight = padding; // Initial top padding
    const elementHeights = [];
    if (titleBlockHeight > 0) {
        elementHeights.push(titleBlockHeight);
    }
    elementHeights.push(scaledImgHeight); // Image is always part of the height calculation
    if (descriptionBlockHeight > 0) {
        elementHeights.push(descriptionBlockHeight);
    }

    if (elementHeights.length === 0) { // Should not happen due to image always being there
        canvasFinalHeight += padding; // Only top and bottom padding
    } else {
        for (let i = 0; i < elementHeights.length; i++) {
            canvasFinalHeight += elementHeights[i];
            if (i < elementHeights.length - 1) { // If not the last element
                canvasFinalHeight += padding; // Add padding between elements
            }
        }
        canvasFinalHeight += padding; // Final bottom padding
    }


    canvas.width = canvasFinalWidth;
    canvas.height = canvasFinalHeight;

    // 6. Draw Background
    ctx.fillStyle = backgroundColor;
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // Helper function to draw wrapped text (centered)
    // Returns the Y coordinate at the bottom of the drawn text block.
    function drawWrappedText(context, text, textFont, textColor, centerX, startY, maxWidth, lineHeight) {
        text = String(text); // Ensure text is a string
        if (text.trim() === "") return startY;
        
        context.font = textFont;
        context.fillStyle = textColor;
        context.textAlign = 'center';
        context.textBaseline = 'top';

        const words = text.split(' ');
        let line = '';
        let currentLineY = startY;

        if (words.every(word => word === "")) return startY;

        for (let n = 0; n < words.length; n++) {
            const testLine = line + words[n] + ' ';
            const metrics = context.measureText(testLine);
            if (metrics.width > maxWidth && line.trim() !== '') {
                context.fillText(line.trim(), centerX, currentLineY);
                line = words[n] + ' ';
                currentLineY += lineHeight;
            } else {
                line = testLine;
            }
        }
        context.fillText(line.trim(), centerX, currentLineY); // Draw the last line
        return currentLineY + lineHeight; // Y right after the last line of text.
    }

    let currentY = padding; // Y-coordinate for the top of the current element.
    const contentXCenter = canvas.width / 2;

    // 7. Draw Title
    if (titleBlockHeight > 0) {
        drawWrappedText(ctx, titleText, titleFullFont, titleColor, contentXCenter, currentY, infographicContentWidth, titleLineHeight);
        currentY += titleBlockHeight + padding; 
    }

    // 8. Draw Image
    // Image is centered horizontally within the (infographicContentWidth-wide) content area.
    const imageDrawX = padding + (infographicContentWidth - scaledImgWidth) / 2;
    ctx.drawImage(tempImgCanvas, imageDrawX, currentY, scaledImgWidth, scaledImgHeight);
    currentY += scaledImgHeight; // Y is now at the bottom of the image
    if (descriptionBlockHeight > 0) { // Add padding only if there's a description following
        currentY += padding;
    }


    // 9. Draw Description
    if (descriptionBlockHeight > 0) {
        drawWrappedText(ctx, descriptionText, descriptionFullFont, descriptionColor, contentXCenter, currentY, infographicContentWidth, descriptionLineHeight);
        // currentY updates not needed after last element as canvas height is fixed
    }
    
    // 10. Return canvas
    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 Infographic Creator is a web-based tool that allows users to create visually appealing infographics by combining images with customized titles and descriptions. Users can upload an original image and specify the title text, font styles, colors, and padding. The tool formats the image and associated text into a well-structured infographic suitable for presentations, educational content, social media, and other digital platforms. It’s particularly useful for educators, marketers, and content creators looking to convey information effectively through visual storytelling.

Leave a Reply

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