Please bookmark this page to avoid losing your image tool!

Image Speech And Voice Overlay Tool

(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.
/**
 * Creates an image with a speech bubble and an optional audio player.
 * The function draws the original image on a canvas, adds a speech bubble with text,
 * and then places the canvas and an audio player inside a container DIV.
 *
 * @param {Image} originalImg The original javascript Image object.
 * @param {string} [text='Hello, world!'] The text to display in the speech bubble.
 * @param {string} [textColor='#000000'] The color of the text (e.g., '#RRGGBB').
 * @param {number} [fontSize=20] The font size of the text in pixels.
 * @param {string} [bubbleColor='#FFFFFF'] The fill color of the speech bubble.
 * @param {string} [borderColor='#000000'] The border color of the speech bubble.
 * @param {string} [bubblePosition='bottomRight'] The position of the speech bubble. Accepts 'topLeft', 'topRight', 'bottomLeft', 'bottomRight'.
 * @param {string} [audioSrc=''] The URL or Base64 data URI for the audio file. If empty, no audio player is added.
 * @param {number} [audioControls=1] Show audio controls. 1 for true, 0 for false.
 * @returns {HTMLDivElement} A DIV element containing the canvas with the speech bubble and an audio player.
 */
function processImage(originalImg, text = 'Hello, world!', textColor = '#000000', fontSize = 20, bubbleColor = '#FFFFFF', borderColor = '#000000', bubblePosition = 'bottomRight', audioSrc = '', audioControls = 1) {

    // 1. Create a container element to hold both canvas and audio
    const container = document.createElement('div');
    container.style.display = 'inline-block';
    container.style.width = `${originalImg.naturalWidth}px`;

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

    // 3. Set canvas dimensions and draw the original image
    canvas.width = originalImg.naturalWidth;
    canvas.height = originalImg.naturalHeight;
    ctx.drawImage(originalImg, 0, 0);

    // --- Prepare for drawing text and bubble ---

    // Ensure fontSize is a number for calculations
    const numericFontSize = parseInt(fontSize, 10) || 20;
    const font = `${numericFontSize}px Arial`;
    ctx.font = font;
    ctx.textBaseline = 'top';

    // Define bubble geometry based on image size
    const padding = 20; // Padding from image edge
    const bubbleWidth = canvas.width * 0.45;
    const cornerRadius = 20;
    const textPadding = 15; // Padding inside the bubble

    // 4. Wrap text to fit inside the bubble
    const maxWidth = bubbleWidth - 2 * textPadding;
    const words = text.split(' ');
    let lines = [];
    let currentLine = words[0] || '';

    for (let i = 1; i < words.length; i++) {
        const word = words[i];
        const width = ctx.measureText(currentLine + " " + word).width;
        if (width < maxWidth) {
            currentLine += " " + word;
        } else {
            lines.push(currentLine);
            currentLine = word;
        }
    }
    lines.push(currentLine);

    // 5. Calculate bubble height dynamically based on text content
    const lineHeight = numericFontSize * 1.2;
    const requiredTextHeight = lines.length * lineHeight;
    // Ensure bubble is tall enough for text and corner radius
    const bubbleHeight = Math.max(requiredTextHeight + 2 * textPadding, 2 * cornerRadius);

    // 6. Determine bubble's top-left (x, y) coordinates based on position
    let bubbleX, bubbleY;
    switch (bubblePosition) {
        case 'topLeft':
            bubbleX = padding;
            bubbleY = padding + 20; // Add extra padding for tail
            break;
        case 'topRight':
            bubbleX = canvas.width - bubbleWidth - padding;
            bubbleY = padding + 20; // Add extra padding for tail
            break;
        case 'bottomLeft':
            bubbleX = padding;
            bubbleY = canvas.height - bubbleHeight - padding - 20;
            break;
        case 'bottomRight':
        default:
            bubbleX = canvas.width - bubbleWidth - padding;
            bubbleY = canvas.height - bubbleHeight - padding - 20;
            break;
    }

    // --- Helper function to draw the bubble with a tail ---
    function drawSpeechBubble(ctx, x, y, w, h, r, pos) {
        const tailHeight = 20;
        const tailWidth = 20;
        ctx.beginPath();
        ctx.fillStyle = bubbleColor;
        ctx.strokeStyle = borderColor;
        ctx.lineWidth = 2;

        // Path drawing logic
        // Top edge
        ctx.moveTo(x + r, y);
        if (pos === 'topLeft') {
            ctx.lineTo(x + w * 0.3, y);
            ctx.lineTo(x + w * 0.3 + tailWidth / 2, y - tailHeight);
            ctx.lineTo(x + w * 0.3 + tailWidth, y);
        } else if (pos === 'topRight') {
            ctx.lineTo(x + w - (w * 0.3) - tailWidth, y);
            ctx.lineTo(x + w - (w * 0.3) - tailWidth / 2, y - tailHeight);
            ctx.lineTo(x + w - (w * 0.3), y);
        }
        ctx.lineTo(x + w - r, y);
        ctx.quadraticCurveTo(x + w, y, x + w, y + r);

        // Right edge
        ctx.lineTo(x + w, y + h - r);
        ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);

        // Bottom edge
        if (pos === 'bottomLeft') {
            ctx.lineTo(x + w * 0.3 + tailWidth, y + h);
            ctx.lineTo(x + w * 0.3 + tailWidth / 2, y + h + tailHeight);
            ctx.lineTo(x + w * 0.3, y + h);
        } else if (pos === 'bottomRight') {
            ctx.lineTo(x + w - (w * 0.3), y + h);
            ctx.lineTo(x + w - (w * 0.3) - tailWidth / 2, y + h + tailHeight);
            ctx.lineTo(x + w - (w * 0.3) - tailWidth, y + h);
        }
        ctx.lineTo(x + r, y + h);
        ctx.quadraticCurveTo(x, y + h, x, y + h - r);

        // Left edge
        ctx.lineTo(x, y + r);
        ctx.quadraticCurveTo(x, y, x + r, y);

        ctx.closePath();
        ctx.fill();
        ctx.stroke();
    }

    // 7. Draw the bubble on the canvas
    drawSpeechBubble(ctx, bubbleX, bubbleY, bubbleWidth, bubbleHeight, cornerRadius, bubblePosition);

    // 8. Draw the wrapped text inside the bubble
    ctx.fillStyle = textColor;
    lines.forEach((line, index) => {
        // Center text horizontally
        const textWidth = ctx.measureText(line).width;
        const textX = bubbleX + (bubbleWidth - textWidth) / 2;
        const textY = bubbleY + textPadding + (index * lineHeight);
        ctx.fillText(line, textX, textY);
    });

    // 9. Append canvas to the container
    container.appendChild(canvas);

    // 10. Create and append audio player if a source is provided
    if (audioSrc && audioSrc.trim() !== '') {
        const audio = document.createElement('audio');
        audio.src = audioSrc;
        if (audioControls === 1) {
            audio.controls = true;
        }
        audio.style.width = '100%';
        audio.style.marginTop = '8px';
        container.appendChild(audio);
    }

    // 11. Return the final container element
    return container;
}

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 Speech and Voice Overlay Tool allows users to create an image that includes a speech bubble displaying custom text and an optional audio player for sound effects or voice narration. Ideal for educators, marketers, and social media users, this tool can be used to enhance images by providing context or commentary, making it perfect for creating engaging visual content such as educational resources, promotional graphics, or entertaining memes with voice overlays.

Leave a Reply

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