Please bookmark this page to avoid losing your image tool!

Image Scout Explorer Badge Template 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.
function processImage(originalImg, topText = "TOP TEXT", bottomText = "BOTTOM TEXT", badgeSize = 200, borderColor = "gold", borderWidth = 10, backgroundColor = "#006400", textColor = "white", fontFamily = "Arial, sans-serif", fontSizeRatio = 0.075, textPaddingFromEdgeRatio = 0.025, imagePadding = 5, textArcAngleDegrees = 90) {

    // Helper function to draw text along an arc
    // - ctx: Canvas 2D rendering context
    // - str: The text string to draw
    // - centerX, centerY: Coordinates of the arc's center
    // - radius: Radius of the arc for the text baseline (middle of text)
    // - textArcAngleDeg: The angular width the text should span
    // - isTop: Boolean, true for top arc, false for bottom arc
    // - calculatedFontSize: The font size in pixels
    // - currentFontFamily: The font family string
    // - currentTextColor: The text color string
    function drawArcedText(ctx, str, centerX, centerY, radius, textArcAngleDeg, isTop, calculatedFontSize, currentFontFamily, currentTextColor) {
        if (!str || str.length === 0 || radius <= 0) return; // Do not draw if no text, or radius is invalid

        const textArcAngleRad = textArcAngleDeg * Math.PI / 180;
        ctx.save();
        ctx.font = `${calculatedFontSize}px ${currentFontFamily}`;
        ctx.fillStyle = currentTextColor;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';

        const len = str.length;
        // Angle step between character centers. If only one char, it's placed at the arc's conformational center.
        const angleStep = (len > 1) ? textArcAngleRad / (len - 1) : 0;

        // Determine the main orientation angle for the arc (-90 degrees for top, +90 for bottom)
        const baseAngle = isTop ? -Math.PI / 2 : Math.PI / 2;
        
        // Starting angle for the first character on the arc
        let currentCharacterAngle = baseAngle - textArcAngleRad / 2;

        if (len === 1) { // Single character, place it at the center of the arc's orientation
            currentCharacterAngle = baseAngle;
        }
        
        for (let i = 0; i < len; i++) {
            ctx.save();
            // Move context to the center of the badge
            ctx.translate(centerX, centerY);
            
            // Calculate rotation for the character's position on the arc AND its individual orientation
            // For top text, characters are upright (tangent + 90deg).
            // For bottom text, characters are also upright relative to viewer (tangent - 90deg, then flipped).
            const charOrientationOnArc = isTop ? currentCharacterAngle + Math.PI / 2 : currentCharacterAngle - Math.PI / 2;
            ctx.rotate(charOrientationOnArc);
            
            // Translate along the (new) Y-axis to the text radius
            // For top text, this is -radius. For bottom text, +radius.
            ctx.translate(0, isTop ? -radius : radius);

            // For bottom text, characters need to be flipped 180 degrees to appear upright to the viewer
            if (!isTop) {
                 ctx.rotate(Math.PI);
            }
            
            ctx.fillText(str[i], 0, 0);
            ctx.restore(); // Restore to context centered at (centerX, centerY) with no rotation

            if (len > 1) { // Increment angle for the next character
                currentCharacterAngle += angleStep;
            }
        }
        ctx.restore(); // Restore to original context state
    }

    const canvas = document.createElement('canvas');
    canvas.width = badgeSize;
    canvas.height = badgeSize;
    const ctx = canvas.getContext('2d');

    const centerX = badgeSize / 2;
    const centerY = badgeSize / 2;

    // Calculate dynamic sizes based on badgeSize and ratios
    const actualFontSize = badgeSize * fontSizeRatio;
    const actualTextPaddingFromEdge = badgeSize * textPaddingFromEdgeRatio;

    // 1. Draw outer border
    if (borderWidth > 0) {
        ctx.beginPath();
        // Arc for border is centered; line width expands inwards and outwards from this path
        ctx.arc(centerX, centerY, badgeSize / 2 - borderWidth / 2, 0, 2 * Math.PI);
        ctx.strokeStyle = borderColor;
        ctx.lineWidth = borderWidth;
        ctx.stroke();
    }

    // 2. Draw background fill
    // Radius of the content area, inside the border
    const contentRadius = Math.max(0, badgeSize / 2 - borderWidth); 
    if (contentRadius > 0) {
        ctx.beginPath();
        ctx.arc(centerX, centerY, contentRadius, 0, 2 * Math.PI);
        ctx.fillStyle = backgroundColor;
        ctx.fill();
    }


    // 3. Draw Texts (Top and Bottom)
    // Calculate the radius for the text baseline (middle of the font height)
    const textBaselineRadius = Math.max(0, contentRadius - actualTextPaddingFromEdge - actualFontSize / 2);
    
    if (topText && topText.length > 0) {
        drawArcedText(ctx, topText, centerX, centerY, textBaselineRadius, textArcAngleDegrees, true, actualFontSize, fontFamily, textColor);
    }
    if (bottomText && bottomText.length > 0) {
        drawArcedText(ctx, bottomText, centerX, centerY, textBaselineRadius, textArcAngleDegrees, false, actualFontSize, fontFamily, textColor);
    }

    // 4. Draw the central image
    // Image is placed in a circle inside the text arcs (if space allows)
    const imageMaxRadius = Math.max(0, textBaselineRadius - actualFontSize / 2 - imagePadding);

    if (originalImg && imageMaxRadius > 0 && originalImg.naturalWidth > 0 && originalImg.naturalHeight > 0) {
        ctx.save();
        ctx.beginPath();
        ctx.arc(centerX, centerY, imageMaxRadius, 0, 2 * Math.PI);
        ctx.clip(); // Clip the drawing area to this circle

        // Scale image to "cover" the circular clip area, preserving aspect ratio
        const imgWidth = originalImg.naturalWidth || originalImg.width;
        const imgHeight = originalImg.naturalHeight || originalImg.height;
        const aspect = imgWidth / imgHeight;
        
        let drawWidth, drawHeight, drawX, drawY;

        // Determine dimensions to make the image cover the circle:
        // The dimension (width or height) that would be smaller (relative to the circle) is scaled up to fill the circle.
        if (aspect >= 1) { // Landscape or square image: height is the relatively "smaller" dimension or equal
            drawHeight = 2 * imageMaxRadius;
            drawWidth = drawHeight * aspect;
        } else { // Portrait image: width is the relatively "smaller" dimension
            drawWidth = 2 * imageMaxRadius;
            drawHeight = drawWidth / aspect;
        }
        
        // Center the image within the circle
        drawX = centerX - drawWidth / 2;
        drawY = centerY - drawHeight / 2;
        
        ctx.drawImage(originalImg, drawX, drawY, drawWidth, drawHeight);
        ctx.restore(); // Remove clipping path
    }
    
    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 Scout Explorer Badge Template Creator allows users to create customized badges by combining images and text in an arc format. Users can upload an image, input top and bottom text, and customize various aspects of the badge such as size, border color, background color, and text styles. This tool is ideal for creating badges for events, recognition, or achievements in educational or community settings, making it a versatile option for educators, youth leaders, and community organizers looking to produce personalized awards or participation badges.

Leave a Reply

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