Please bookmark this page to avoid losing your image tool!

Image Help Assistant

(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.
function processImage(originalImg, message = "На помощь!", assistantType = "robot", bubbleColor = "#ffeb3b") {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    
    // Match dimensions of the original image
    const w = originalImg.width;
    const h = originalImg.height;
    
    canvas.width = w;
    canvas.height = h;
    
    // Draw original picture
    ctx.drawImage(originalImg, 0, 0, w, h);
    
    // Calculate adaptive scaling so "assistant" looks proportionate
    // Min scale of 0.8 to ensure text stays readable on smaller pictures
    const scale = Math.max(0.8, Math.min(w, h) / 400); 
    
    const fontSize = Math.floor(22 * scale);
    const padding = Math.floor(15 * scale);
    const margin = Math.floor(20 * scale);
    const lineHeight = fontSize * 1.4;
    const maxTextWidth = Math.max(150 * scale, w * 0.45); 
    
    ctx.font = `bold ${fontSize}px "Comic Sans MS", "Segoe UI", Arial, sans-serif`;
    
    // Figure out the preferred assistant mascot
    let mascot = "🤖";
    const typeLower = assistantType.toLowerCase();
    if (typeLower.includes("doc")) mascot = "👨‍⚕️";
    if (typeLower.includes("dog")) mascot = "🐶";
    if (typeLower.includes("sos") || typeLower.includes("help")) mascot = "🛟";
    if (typeLower.includes("clip")) mascot = "📎";
    
    // Text Wrapping Logic
    const words = message.split(' ');
    let line = '';
    const lines = [];
    let longestLineWidth = 0;
    
    for (let n = 0; n < words.length; n++) {
        const testLine = line + words[n] + ' ';
        const metrics = ctx.measureText(testLine);
        const testWidth = metrics.width;
        
        if (testWidth > maxTextWidth && n > 0) {
            lines.push(line);
            line = words[n] + ' ';
        } else {
            line = testLine;
        }
    }
    lines.push(line);
    
    // Verify sizes
    lines.forEach(l => {
        const lw = ctx.measureText(l).width;
        if (lw > longestLineWidth) longestLineWidth = lw;
    });
    
    const textBlockWidth = longestLineWidth;
    const textBlockHeight = lines.length * lineHeight;
    
    // Calculate bubble dimensions
    const bubbleW = textBlockWidth + padding * 2;
    // Deduct slightly bounds since trailing space might exist on font baseline
    const bubbleH = textBlockHeight + padding * 2 - (lineHeight - fontSize); 
    
    const emojiSize = Math.floor(55 * scale);
    ctx.font = `${emojiSize}px sans-serif`;
    const emojiWidth = ctx.measureText(mascot).width;
    
    // Element positions
    const emojiX = w - emojiWidth - margin;
    const emojiY = h - margin; 
    
    let bubbleX = emojiX - bubbleW - margin / 2;
    const bubbleY = Math.max(margin, h - margin - emojiSize / 2 - bubbleH / 2);
    
    // Force bubble to stay within canvas bounds
    if (bubbleX < margin) bubbleX = margin; 
    
    // Draw Speech Bubble Visuals
    ctx.fillStyle = bubbleColor;
    ctx.shadowColor = 'rgba(0,0,0,0.35)';
    ctx.shadowBlur = 10 * scale;
    ctx.shadowOffsetX = 3 * scale;
    ctx.shadowOffsetY = 5 * scale;
    
    const radius = 15 * scale;
    
    ctx.beginPath();
    ctx.moveTo(bubbleX + radius, bubbleY);
    
    // Top Edge
    ctx.lineTo(bubbleX + bubbleW - radius, bubbleY);
    ctx.quadraticCurveTo(bubbleX + bubbleW, bubbleY, bubbleX + bubbleW, bubbleY + radius);
    
    // Right Edge logic (Add tail if the bubble is left of the emoji)
    if (bubbleX + bubbleW < emojiX) {
        const tailY = bubbleY + Math.max(radius, bubbleH / 2 - 15 * scale);
        ctx.lineTo(bubbleX + bubbleW, tailY);
        // Triangle tail pointing to mascot
        ctx.lineTo(emojiX + emojiWidth / 4, tailY + 15 * scale);
        ctx.lineTo(bubbleX + bubbleW, tailY + 20 * scale);
    }
    
    ctx.lineTo(bubbleX + bubbleW, bubbleY + bubbleH - radius);
    ctx.quadraticCurveTo(bubbleX + bubbleW, bubbleY + bubbleH, bubbleX + bubbleW - radius, bubbleY + bubbleH);
    
    // Bottom Edge
    ctx.lineTo(bubbleX + radius, bubbleY + bubbleH);
    ctx.quadraticCurveTo(bubbleX, bubbleY + bubbleH, bubbleX, bubbleY + bubbleH - radius);
    
    // Left Edge
    ctx.lineTo(bubbleX, bubbleY + radius);
    ctx.quadraticCurveTo(bubbleX, bubbleY, bubbleX + radius, bubbleY);
    
    ctx.closePath();
    
    // Render Bubble
    ctx.fill();
    ctx.shadowColor = 'transparent'; 
    ctx.lineWidth = 2 * Math.max(1, scale);
    ctx.strokeStyle = '#222222';
    ctx.stroke();
    
    // Draw Helper Message Text
    ctx.fillStyle = '#111111';
    ctx.textAlign = 'left';
    ctx.textBaseline = 'top';
    ctx.font = `bold ${fontSize}px "Comic Sans MS", "Segoe UI", Arial, sans-serif`;
    
    let textY = bubbleY + padding;
    lines.forEach(l => {
        ctx.fillText(l.trim(), bubbleX + padding, textY);
        textY += lineHeight;
    });
    
    // Draw Assistant Mascot (Emoji)
    ctx.font = `${emojiSize}px sans-serif`;
    ctx.textAlign = 'left';
    ctx.textBaseline = 'bottom';
    
    // Drop shadow for the emoji
    ctx.shadowColor = 'rgba(0,0,0,0.5)';
    ctx.shadowBlur = 8 * scale;
    ctx.shadowOffsetX = 2 * scale;
    ctx.shadowOffsetY = 4 * scale;
    
    ctx.fillText(mascot, emojiX, emojiY);
    
    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 Help Assistant is a creative tool that allows you to add custom speech bubbles and mascot emojis to your images. You can personalize the assistant’s appearance by selecting different mascot types (such as a robot, doctor, dog, or lifebuoy) and choosing a custom bubble color. This tool is ideal for creating expressive memes, adding instructional callouts to tutorials, or adding playful characters to photos for social media and presentations.

Leave a Reply

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