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!
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.