You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(
originalImg,
celebrityType = 'Pop Star',
position = 'Right',
autographText = 'С любовью, твоя Звезда!',
autographColor = 'white'
) {
const canvas = document.createElement('canvas');
canvas.width = originalImg.width;
canvas.height = originalImg.height;
const ctx = canvas.getContext('2d');
// Draw original image as the background (the selfie)
ctx.drawImage(originalImg, 0, 0);
// Helpers to draw stylized vector celebrities
function drawPopStar(ctx, x, y, size) {
ctx.save();
ctx.translate(x, y);
ctx.scale(size, size);
ctx.fillStyle = '#222';
ctx.beginPath();
ctx.moveTo(-120, 1000);
ctx.lineTo(-120, 120);
ctx.quadraticCurveTo(-120, 80, -40, 80);
ctx.lineTo(-20, 100);
ctx.lineTo(20, 100);
ctx.lineTo(40, 80);
ctx.quadraticCurveTo(120, 80, 120, 120);
ctx.lineTo(120, 1000);
ctx.fill();
ctx.fillStyle = '#eeeeee';
ctx.beginPath();
ctx.moveTo(-20, 100);
ctx.lineTo(20, 100);
ctx.lineTo(0, 250);
ctx.fill();
ctx.fillStyle = '#e74c3c';
ctx.beginPath();
ctx.moveTo(-5, 100);
ctx.lineTo(5, 100);
ctx.lineTo(10, 160);
ctx.lineTo(0, 190);
ctx.lineTo(-10, 160);
ctx.fill();
ctx.fillStyle = '#ffc299';
ctx.fillRect(-15, 40, 30, 60);
ctx.beginPath();
ctx.arc(0, 0, 55, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#3e2723';
ctx.beginPath();
ctx.moveTo(-55, 0);
ctx.quadraticCurveTo(-65, -80, -20, -80);
ctx.quadraticCurveTo(0, -100, 30, -70);
ctx.quadraticCurveTo(65, -50, 55, 0);
ctx.quadraticCurveTo(20, -25, -55, 0);
ctx.fill();
ctx.fillStyle = '#111';
ctx.beginPath();
ctx.moveTo(-50, -10);
ctx.lineTo(50, -10);
ctx.lineTo(45, 15);
ctx.lineTo(15, 15);
ctx.lineTo(5, -2);
ctx.lineTo(-5, -2);
ctx.lineTo(-15, 15);
ctx.lineTo(-45, 15);
ctx.fill();
ctx.fillStyle = 'rgba(255,255,255,0.2)';
ctx.fillRect(-35, -5, 15, 15);
ctx.fillRect(20, -5, 15, 15);
ctx.strokeStyle = '#a0522d';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.arc(0, 25, 20, 0, Math.PI);
ctx.stroke();
ctx.restore();
}
function drawActress(ctx, x, y, size) {
ctx.save();
ctx.translate(x, y);
ctx.scale(size, size);
ctx.fillStyle = '#c0392b';
ctx.beginPath();
ctx.moveTo(-100, 1000);
ctx.lineTo(-100, 150);
ctx.quadraticCurveTo(-80, 110, -40, 100);
ctx.lineTo(40, 100);
ctx.quadraticCurveTo(80, 110, 100, 150);
ctx.lineTo(100, 1000);
ctx.fill();
ctx.fillStyle = '#ffe0bd';
ctx.fillRect(-15, 40, 30, 60);
ctx.beginPath();
ctx.arc(0, 0, 50, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#c0392b';
ctx.beginPath();
ctx.arc(0, 25, 15, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#111';
ctx.beginPath();
ctx.arc(-22, -5, 22, 0, Math.PI * 2);
ctx.arc(22, -5, 22, 0, Math.PI * 2);
ctx.fill();
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(-22, -5);
ctx.lineTo(22, -5);
ctx.stroke();
ctx.fillStyle = '#f1c40f';
ctx.beginPath();
ctx.arc(-35, -20, 35, 0, Math.PI * 2);
ctx.arc(35, -20, 35, 0, Math.PI * 2);
ctx.arc(0, -45, 45, 0, Math.PI * 2);
ctx.arc(-45, 30, 30, 0, Math.PI * 2);
ctx.arc(45, 30, 30, 0, Math.PI * 2);
ctx.arc(-40, 70, 30, 0, Math.PI * 2);
ctx.arc(40, 70, 30, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
function drawRocker(ctx, x, y, size) {
ctx.save();
ctx.translate(x, y);
ctx.scale(size, size);
ctx.fillStyle = '#1a1a1a';
ctx.beginPath();
ctx.moveTo(-110, 1000);
ctx.lineTo(-110, 140);
ctx.quadraticCurveTo(-100, 100, -45, 90);
ctx.lineTo(45, 90);
ctx.quadraticCurveTo(100, 100, 110, 140);
ctx.lineTo(110, 1000);
ctx.fill();
ctx.fillStyle = '#444';
ctx.beginPath();
ctx.moveTo(-25, 90);
ctx.lineTo(25, 90);
ctx.lineTo(0, 250);
ctx.fill();
ctx.fillStyle = '#e8b87d';
ctx.fillRect(-18, 40, 36, 60);
ctx.beginPath();
ctx.arc(0, 0, 52, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#222';
ctx.beginPath();
ctx.arc(0, 30, 15, 0, Math.PI, true);
ctx.fill();
ctx.fillStyle = '#2c3e50';
ctx.beginPath();
ctx.moveTo(-48, -10);
ctx.lineTo(48, -10);
ctx.lineTo(38, 15);
ctx.lineTo(8, 15);
ctx.lineTo(0, -5);
ctx.lineTo(-8, 15);
ctx.lineTo(-38, 15);
ctx.fill();
ctx.strokeStyle = '#1a1a1a';
ctx.lineWidth = 18;
ctx.lineCap = 'round';
for(let i = -1; i <= 1; i += 2) {
ctx.beginPath();
ctx.moveTo(i * 25, -40);
ctx.quadraticCurveTo(i * 65, -30, i * 55, 60);
ctx.quadraticCurveTo(i * 45, 120, i * 55, 140);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(i * 10, -45);
ctx.quadraticCurveTo(i * 55, -20, i * 45, 100);
ctx.stroke();
}
ctx.fillStyle = '#8e44ad';
ctx.fillRect(-50, -35, 100, 18);
ctx.restore();
}
function drawHipHopStar(ctx, x, y, size) {
ctx.save();
ctx.translate(x, y);
ctx.scale(size, size);
ctx.fillStyle = '#27ae60';
ctx.beginPath();
ctx.moveTo(-130, 1000);
ctx.lineTo(-130, 150);
ctx.quadraticCurveTo(-110, 80, -40, 80);
ctx.lineTo(40, 80);
ctx.quadraticCurveTo(110, 80, 130, 150);
ctx.lineTo(130, 1000);
ctx.fill();
ctx.strokeStyle = '#f1c40f';
ctx.lineWidth = 6;
ctx.beginPath();
ctx.arc(0, 120, 40, 0, Math.PI);
ctx.stroke();
ctx.fillStyle = '#f1c40f';
ctx.fillRect(-12, 160, 24, 24);
ctx.fillStyle = '#8d6e63';
ctx.fillRect(-20, 30, 40, 60);
ctx.beginPath();
ctx.arc(0, 0, 52, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#e74c3c';
ctx.beginPath();
ctx.arc(0, -10, 53, Math.PI, 2 * Math.PI);
ctx.fill();
ctx.fillRect(-53, -10, 106, 10);
ctx.fillRect(40, -10, 30, 8);
ctx.fillStyle = '#ecf0f1';
ctx.fillRect(-45, -5, 40, 25);
ctx.fillRect(5, -5, 40, 25);
ctx.fillStyle = '#111';
ctx.fillRect(-40, 0, 30, 15);
ctx.fillRect(10, 0, 30, 15);
ctx.fillStyle = '#3e2723';
ctx.beginPath();
ctx.arc(0, 35, 10, 0, Math.PI, false);
ctx.fill();
ctx.restore();
}
// Attempt to dynamically load Google's "Caveat" handwriting font for the best looking autograph effect
async function loadHandwritingFont() {
const fontName = 'Caveat';
if (!document.getElementById('font-caveat')) {
const style = document.createElement('style');
style.id = 'font-caveat';
style.textContent = `@import url('https://fonts.googleapis.com/css2?family=Caveat:wght@700&display=swap');`;
document.head.appendChild(style);
const hiddenDiv = document.createElement('div');
hiddenDiv.style.fontFamily = `"${fontName}"`;
hiddenDiv.style.visibility = 'hidden';
hiddenDiv.style.position = 'absolute';
hiddenDiv.style.top = '-9999px';
hiddenDiv.textContent = 'Autograph Автограф Selfie Звезда';
document.body.appendChild(hiddenDiv);
try {
await document.fonts.ready;
await document.fonts.load(`700 16px "${fontName}"`);
} catch (e) {
console.warn("Could not dynamically load Google Fonts. Falling back to native system fonts.");
}
}
}
await loadHandwritingFont();
// Determine proportions for the vector drawings
let size = Math.min(canvas.height / 450, canvas.width / 350);
const y = canvas.height * 0.35 + (size * 10);
const posStr = (position || 'Right').toLowerCase();
const isRight = posStr !== 'left';
const x = isRight ? canvas.width - (size * 130) : size * 130;
const celebId = (celebrityType || 'Pop Star').toLowerCase().trim();
const displayName = (celebrityType || 'Pop Star');
// Draw the generated celebrity vector character
if (celebId === 'actress') {
drawActress(ctx, x, y, size);
} else if (celebId === 'rock legend' || celebId === 'rock star') {
drawRocker(ctx, x, y, size);
} else if (celebId === 'hip hop star' || celebId === 'rapper') {
drawHipHopStar(ctx, x, y, size);
} else {
drawPopStar(ctx, x, y, size); // fallback to general 'Pop Star'
}
// Add signed autograph effect overlay
const fontSize = Math.min(canvas.width / 15, canvas.height / 10);
ctx.font = `700 ${fontSize}px "Caveat", "Brush Script MT", "Comic Sans MS", cursive`;
const textX = isRight ? canvas.width * 0.05 : canvas.width * 0.95;
const textY = canvas.height * 0.85;
ctx.save();
ctx.translate(textX, textY);
ctx.rotate(-12 * Math.PI / 180); // Tilt autograph slightly
ctx.textAlign = isRight ? 'left' : 'right';
ctx.shadowColor = 'rgba(0,0,0,0.8)';
ctx.shadowBlur = fontSize * 0.3;
ctx.shadowOffsetX = fontSize * 0.05;
ctx.shadowOffsetY = fontSize * 0.05;
ctx.fillStyle = autographColor || 'white';
ctx.fillText(autographText || 'С любовью, твоя Звезда!', 0, 0);
// Sub-signature (the selected celebrity category name)
ctx.font = `700 ${fontSize * 0.6}px "Caveat", "Brush Script MT", "Comic Sans MS", cursive`;
ctx.fillText("- " + displayName, isRight ? fontSize : -fontSize, fontSize * 1.2);
ctx.restore();
return canvas;
}
Apply Changes