Please bookmark this page to avoid losing your image tool!

Image Product Adder

(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, productsData = '[]') {
    /**
     * Dynamically loads the 'Poppins' Google Font if it hasn't been loaded yet.
     * This is done only once to improve performance on subsequent calls.
     */
    if (!processImage.fontLoaded) {
        try {
            const fontPoppins = new FontFace(
                'Poppins',
                'url(https://fonts.gstatic.com/s/poppins/v20/pxiByp8kv8JHgFVrLGT9Z1xlFQ.woff2)', {
                    style: 'normal',
                    weight: '400'
                }
            );
            const fontPoppinsBold = new FontFace(
                'Poppins',
                'url(https://fonts.gstatic.com/s/poppins/v20/pxiEyp8kv8JHgFVrJJbecmNE.woff2)', {
                    style: 'normal',
                    weight: '700'
                }
            );
            // Wait for both font weights to be loaded
            await Promise.all([fontPoppins.load(), fontPoppinsBold.load()]);
            // Add the fonts to the document's font set
            document.fonts.add(fontPoppins);
            document.fonts.add(fontPoppinsBold);
            processImage.fontLoaded = true;
        } catch (e) {
            console.error("Could not load the 'Poppins' font. Using a fallback sans-serif font.", e);
            // Mark as loaded even if it fails, to avoid retrying.
            processImage.fontLoaded = true;
        }
    }

    // 1. Set up the canvas
    const canvas = document.createElement('canvas');
    canvas.width = originalImg.naturalWidth;
    canvas.height = originalImg.naturalHeight;
    const ctx = canvas.getContext('2d');

    // 2. Draw the original image as the background
    ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);

    // 3. Parse the product data from the JSON string
    let products = [];
    try {
        const parsedData = JSON.parse(productsData);
        if (Array.isArray(parsedData)) {
            products = parsedData;
        } else {
            console.warn("Provided productsData is not a valid JSON array. No products will be added.");
        }
    } catch (e) {
        console.error("Error parsing productsData JSON string. Please check the format.", e);
        return canvas; // Return the canvas with only the base image
    }

    // 4. Draw a tag for each product
    products.forEach(product => {
        const pX = Number(product.x);
        const pY = Number(product.y);
        const name = String(product.name || 'Unnamed Product');
        const price = String(product.price || '');

        // Skip products with invalid coordinates
        if (isNaN(pX) || isNaN(pY)) {
            return;
        }

        // --- Define Tag Styles and Dimensions ---
        const hotspotRadius = 8;
        const lineLength = 45;
        const padding = 12;
        const lineSpacing = 6;
        const fontFamily = 'Poppins, sans-serif';
        const nameFontSize = 16;
        const priceFontSize = 14;

        // --- Calculate Text and Box Dimensions ---
        ctx.font = `bold ${nameFontSize}px ${fontFamily}`;
        const nameMetrics = ctx.measureText(name);
        ctx.font = `${priceFontSize}px ${fontFamily}`;
        const priceMetrics = ctx.measureText(price);

        const boxWidth = Math.max(nameMetrics.width, priceMetrics.width) + padding * 2;
        const boxHeight = nameFontSize + (price ? priceFontSize + lineSpacing : 0) + padding * 2;

        // --- Position the Tag ---
        // The tag line will point radially away from the center of the image for a clean layout.
        const angle = Math.atan2(pY - canvas.height / 2, pX - canvas.width / 2);
        const lineEndX = pX + lineLength * Math.cos(angle);
        const lineEndY = pY + lineLength * Math.sin(angle);

        // Position the info box relative to the end of the line
        let boxX = lineEndX;
        let boxY = lineEndY - boxHeight / 2; // Vertically center the box

        // If the line points left, anchor the box on its right side
        if (Math.cos(angle) < 0) {
            boxX -= boxWidth;
        }

        // --- Prevent the box from going off-screen ---
        const margin = 5;
        if (boxX < margin) boxX = margin;
        if (boxX + boxWidth > canvas.width - margin) boxX = canvas.width - boxWidth - margin;
        if (boxY < margin) boxY = margin;
        if (boxY + boxHeight > canvas.height - margin) boxY = canvas.height - boxHeight - margin;

        // --- Draw the Tag Elements ---
        // Save context state to apply shadow only to the box
        ctx.save();
        ctx.shadowColor = 'rgba(0, 0, 0, 0.25)';
        ctx.shadowBlur = 8;
        ctx.shadowOffsetY = 3;

        // Draw the info box background
        ctx.fillStyle = 'rgba(255, 255, 255, 0.95)';
        ctx.strokeStyle = 'rgba(0, 0, 0, 0.1)';
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.rect(boxX, boxY, boxWidth, boxHeight);
        ctx.fill();
        ctx.stroke();
        ctx.restore(); // Restore context to remove shadow for other elements

        // Draw the connecting line
        ctx.beginPath();
        ctx.moveTo(pX, pY);
        ctx.lineTo(lineEndX, lineEndY);
        ctx.strokeStyle = '#333333';
        ctx.lineWidth = 1.5;
        ctx.stroke();

        // Draw the product name and price text
        ctx.textAlign = 'left';
        ctx.textBaseline = 'top';
        ctx.fillStyle = '#111111';
        ctx.font = `bold ${nameFontSize}px ${fontFamily}`;
        ctx.fillText(name, boxX + padding, boxY + padding);
        if (price) {
            ctx.fillStyle = '#444444';
            ctx.font = `${priceFontSize}px ${fontFamily}`;
            ctx.fillText(price, boxX + padding, boxY + padding + nameFontSize + lineSpacing);
        }

        // Draw the hotspot circle on top of all other elements
        ctx.lineWidth = 2;
        ctx.strokeStyle = '#333333';
        ctx.fillStyle = '#ffffff';
        ctx.beginPath();
        ctx.arc(pX, pY, hotspotRadius, 0, 2 * Math.PI);
        ctx.fill();
        ctx.stroke();
        // Draw inner dot
        ctx.fillStyle = '#333333';
        ctx.beginPath();
        ctx.arc(pX, pY, hotspotRadius / 2.5, 0, 2 * Math.PI);
        ctx.fill();
    });

    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 Product Adder tool allows users to enhance images by adding product tags directly onto them. By enabling users to specify product data, including names and prices, and their positions on the image, the tool dynamically generates a visually appealing overlay. This is ideal for creating promotional material, such as advertisements or product showcases, where you want to highlight specific items. Marketers and e-commerce businesses can benefit from this tool to better illustrate products in their imagery, making it easier for customers to see details and pricing information directly in context.

Leave a Reply

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