You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, awardText = "AWARD OF#EXCELLENCE", ribbonColor = "#0D2C54", medalColor = "#FFD700", textColor = "#F0F0F0") {
// 1. Create a new canvas and get its 2D context
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 2. Define dimensions based on the original image size
// The medal's diameter will be based on the smaller dimension of the image.
const imgMinDim = Math.min(originalImg.width, originalImg.height);
const medalRadius = imgMinDim / 2 * 1.1; // Make the medal a bit bigger than half the image's smallest side
// Set canvas size to accommodate the medal and ribbon
const canvasWidth = medalRadius * 3;
const canvasHeight = medalRadius * 3.5;
canvas.width = canvasWidth;
canvas.height = canvasHeight;
// Center point for the medal
const centerX = canvasWidth / 2;
const centerY = medalRadius * 1.2;
// 3. Draw the prize ribbon
ctx.fillStyle = ribbonColor;
const tailWidth = medalRadius * 0.8;
const tailHeight = medalRadius * 2;
const vCutHeight = medalRadius * 0.5;
// Draw the two tails of the ribbon as two overlapping polygons for a 3D effect.
// Left tail
ctx.beginPath();
ctx.moveTo(centerX, centerY - 20); // Point behind the medal
ctx.lineTo(centerX - tailWidth, centerY + 20); // Top-left of the visible part
ctx.lineTo(centerX - tailWidth, centerY + tailHeight); // Bottom-left
ctx.lineTo(centerX - tailWidth / 2, centerY + tailHeight - vCutHeight); // V-cut
ctx.lineTo(centerX, centerY + tailHeight); // Bottom-center
ctx.closePath();
ctx.fill();
// Right tail
ctx.beginPath();
ctx.moveTo(centerX, centerY - 20); // Point behind the medal
ctx.lineTo(centerX + tailWidth, centerY + 20); // Top-right of the visible part
ctx.lineTo(centerX + tailWidth, centerY + tailHeight); // Bottom-right
ctx.lineTo(centerX + tailWidth / 2, centerY + tailHeight - vCutHeight); // V-cut
ctx.lineTo(centerX, centerY + tailHeight); // Bottom-center (overlaps left tail)
ctx.closePath();
ctx.fill();
// 4. Draw the medal with a shadow for depth
ctx.shadowColor = 'rgba(0, 0, 0, 0.4)';
ctx.shadowBlur = 15;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 8;
ctx.fillStyle = medalColor;
ctx.beginPath();
ctx.arc(centerX, centerY, medalRadius, 0, 2 * Math.PI);
ctx.fill();
// Reset shadow for subsequent drawings
ctx.shadowColor = 'transparent';
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
// Add a subtle inner border to the medal
ctx.strokeStyle = "rgba(0,0,0,0.2)";
ctx.lineWidth = 3;
ctx.beginPath();
ctx.arc(centerX, centerY, medalRadius - 2, 0, 2 * Math.PI);
ctx.stroke();
// 5. Draw the source image inside the medal
const imageRadius = medalRadius * 0.9; // Make the image slightly smaller than the medal
ctx.save();
ctx.beginPath();
ctx.arc(centerX, centerY, imageRadius, 0, 2 * Math.PI);
ctx.clip(); // Create a circular clipping path
// Apply a "golden" filter to make the image look more prestigious
ctx.filter = 'sepia(80%) brightness(105%) contrast(110%)';
// Calculate dimensions to draw the image, ensuring it fills the circle (cover)
const imgAspectRatio = originalImg.width / originalImg.height;
const circleAspectRatio = 1; // A circle's aspect ratio is 1:1
let drawWidth, drawHeight, drawX, drawY;
if (imgAspectRatio > circleAspectRatio) { // Image is wider than a square
drawHeight = imageRadius * 2;
drawWidth = drawHeight * imgAspectRatio;
} else { // Image is taller than or is a square
drawWidth = imageRadius * 2;
drawHeight = drawWidth / imgAspectRatio;
}
drawX = centerX - drawWidth / 2;
drawY = centerY - drawHeight / 2;
ctx.drawImage(originalImg, drawX, drawY, drawWidth, drawHeight);
ctx.restore(); // Remove the filter and the clipping path
// 6. Draw the award text
ctx.fillStyle = textColor;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// Use a '#' in the string to indicate a line break
const [line1, line2] = awardText.split('#');
if (line1) {
ctx.font = `bold ${medalRadius * 0.18}px 'Georgia', serif`;
ctx.fillText(line1.toUpperCase(), centerX, centerY - medalRadius - 30);
}
if (line2) {
ctx.font = `bold ${medalRadius * 0.25}px 'Georgia', serif`;
ctx.fillText(line2.toUpperCase(), centerX, centerY + medalRadius + 45);
}
// 7. Helper function to draw a star
const drawStar = (cx, cy, spikes, outerRadius, innerRadius) => {
let rot = Math.PI / 2 * 3;
let x = cx;
let y = cy;
let step = Math.PI / spikes;
ctx.beginPath();
ctx.moveTo(cx, cy - outerRadius);
for (let i = 0; i < spikes; i++) {
x = cx + Math.cos(rot) * outerRadius;
y = cy + Math.sin(rot) * outerRadius;
ctx.lineTo(x, y);
rot += step;
x = cx + Math.cos(rot) * innerRadius;
y = cy + Math.sin(rot) * innerRadius;
ctx.lineTo(x, y);
rot += step;
}
ctx.lineTo(cx, cy - outerRadius);
ctx.closePath();
ctx.fill();
};
// Draw three stars at the bottom
ctx.fillStyle = medalColor;
const starOuterRadius = medalRadius * 0.1;
const starInnerRadius = starOuterRadius / 2;
const starY = centerY + tailHeight + medalRadius * 0.1;
drawStar(centerX, starY, 5, starOuterRadius * 1.2, starInnerRadius * 1.2);
drawStar(centerX - starOuterRadius * 2.5, starY - starOuterRadius*0.2, 5, starOuterRadius, starInnerRadius);
drawStar(centerX + starOuterRadius * 2.5, starY - starOuterRadius*0.2, 5, starOuterRadius, starInnerRadius);
// 8. Return the final canvas, which can be displayed directly.
return canvas;
}
Apply Changes