You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, operationMode = 'photobomb', position = 'bottom-right') {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (operationMode === 'portrait') {
// Portrait Mode: Turn the uploaded image into a Domovoy character
canvas.width = 600;
canvas.height = 600;
// 1. Background (Wooden hut planks)
ctx.fillStyle = '#8B5A2B';
ctx.fillRect(0, 0, 600, 600);
ctx.strokeStyle = '#5C3A21';
ctx.lineWidth = 4;
for (let i = 0; i < 600; i += 80) {
ctx.beginPath();
ctx.moveTo(0, i);
ctx.lineTo(600, i);
ctx.stroke();
// Draw some knotholes in the wood
if (i % 160 === 0) {
ctx.beginPath();
ctx.ellipse(100 + i / 2, i + 40, 20, 5, 0, 0, Math.PI * 2);
ctx.stroke();
ctx.beginPath();
ctx.ellipse(100 + i / 2, i + 40, 10, 2, 0, 0, Math.PI * 2);
ctx.stroke();
}
}
// 2. Body (Traditional red shirt - Kosovorotka)
ctx.fillStyle = '#C21E56';
ctx.beginPath();
ctx.moveTo(220, 320);
ctx.quadraticCurveTo(100, 450, 80, 600);
ctx.lineTo(520, 600);
ctx.quadraticCurveTo(500, 450, 380, 320);
ctx.fill();
// Shirt pattern (polka dots)
ctx.fillStyle = 'rgba(255, 255, 255, 0.4)';
for (let i = 0; i < 30; i++) {
ctx.beginPath();
ctx.arc(100 + Math.random() * 400, 350 + Math.random() * 250, 4, 0, Math.PI * 2);
ctx.fill();
}
// Collar
ctx.fillStyle = '#FFF';
ctx.fillRect(290, 320, 20, 120);
// Arms
ctx.fillStyle = '#B31B4D';
ctx.beginPath();
ctx.moveTo(170, 400); // Left arm
ctx.lineTo(60, 500);
ctx.lineTo(90, 530);
ctx.lineTo(200, 480);
ctx.fill();
ctx.beginPath();
ctx.moveTo(430, 400); // Right arm
ctx.lineTo(540, 500);
ctx.lineTo(510, 530);
ctx.lineTo(400, 480);
ctx.fill();
// Props (Spoon & Broom)
// Left - Wooden Spoon
ctx.save();
ctx.translate(75, 515);
ctx.rotate(-Math.PI / 4);
ctx.fillStyle = '#D2B48C';
ctx.fillRect(-5, -80, 10, 80);
ctx.beginPath();
ctx.ellipse(0, -90, 20, 30, 0, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
// Right - Besom (Broom)
ctx.save();
ctx.strokeStyle = '#8B5A2B';
ctx.lineWidth = 10;
ctx.beginPath();
ctx.moveTo(540, 350);
ctx.lineTo(510, 600);
ctx.stroke();
ctx.fillStyle = '#DEB887';
ctx.beginPath();
ctx.moveTo(540, 350);
ctx.lineTo(500, 200);
ctx.lineTo(580, 200);
ctx.fill();
ctx.strokeStyle = '#CD853F';
ctx.lineWidth = 2;
for (let i = 0; i < 16; i++) {
ctx.beginPath();
ctx.moveTo(540, 350);
ctx.lineTo(500 + i * 5.3, 200);
ctx.stroke();
}
ctx.strokeStyle = '#8B5A2B';
ctx.lineWidth = 4;
ctx.beginPath();
ctx.moveTo(525, 320);
ctx.lineTo(555, 315);
ctx.stroke();
ctx.restore();
// Hands (Drawn over props)
ctx.fillStyle = '#E8B48F';
ctx.beginPath();
ctx.arc(75, 515, 20, 0, Math.PI * 2);
ctx.arc(525, 515, 20, 0, Math.PI * 2);
ctx.fill();
// 3. User Image (Cropped inside the Face)
ctx.save();
ctx.beginPath();
ctx.arc(300, 250, 95, 0, Math.PI * 2);
ctx.closePath();
ctx.clip();
const imgAspect = originalImg.width / originalImg.height;
let drawW, drawH;
if (imgAspect > 1) {
drawH = 190;
drawW = 190 * imgAspect;
} else {
drawW = 190;
drawH = 190 / imgAspect;
}
ctx.drawImage(originalImg, 300 - drawW / 2, 250 - drawH / 2, drawW, drawH);
ctx.restore();
// 4. Beard and Hair (Frames the face to complete the Domovoy look)
ctx.fillStyle = '#4A3326';
const beardCircles = [
{ x: 215, y: 280, r: 40 }, { x: 235, y: 320, r: 45 }, { x: 265, y: 350, r: 50 },
{ x: 300, y: 360, r: 55 }, { x: 335, y: 350, r: 50 }, { x: 365, y: 320, r: 45 },
{ x: 385, y: 280, r: 40 }
];
beardCircles.forEach(c => {
ctx.beginPath(); ctx.arc(c.x, c.y, c.r, 0, Math.PI * 2); ctx.fill();
});
const hairCircles = [
{ x: 210, y: 210, r: 40 }, { x: 230, y: 160, r: 45 }, { x: 265, y: 130, r: 50 },
{ x: 300, y: 120, r: 55 }, { x: 335, y: 130, r: 50 }, { x: 370, y: 160, r: 45 },
{ x: 390, y: 210, r: 40 }
];
hairCircles.forEach(c => {
ctx.beginPath(); ctx.arc(c.x, c.y, c.r, 0, Math.PI * 2); ctx.fill();
});
// Inner lighter texture loops for volume
ctx.fillStyle = '#6E4D3A';
beardCircles.forEach(c => {
ctx.beginPath(); ctx.arc(c.x, c.y - 5, c.r * 0.6, 0, Math.PI * 2); ctx.fill();
});
hairCircles.forEach(c => {
ctx.beginPath(); ctx.arc(c.x, c.y + 5, c.r * 0.6, 0, Math.PI * 2); ctx.fill();
});
// 5. Title Text
ctx.fillStyle = '#4A3326';
ctx.font = 'bold 46px "Trebuchet MS", "Arial", sans-serif';
ctx.textAlign = 'center';
ctx.fillText('ДОМОВОЙ', 303, 63);
ctx.fillStyle = '#FFD700';
ctx.fillText('ДОМОВОЙ', 300, 60);
} else {
// Photobomb Mode: Add a mini Domovoy secretly visiting your photo
canvas.width = originalImg.width;
canvas.height = originalImg.height;
ctx.drawImage(originalImg, 0, 0);
const size = Math.max(100, Math.min(originalImg.height, originalImg.width) * 0.4);
const marginX = size * 0.4;
const marginY = 0;
// Positioning logic
let cx, cy;
switch (position) {
case 'bottom-left':
cx = marginX; cy = originalImg.height - marginY; break;
case 'top-left':
cx = marginX; cy = size; break;
case 'top-right':
cx = originalImg.width - marginX; cy = size; break;
case 'bottom-right':
default:
cx = originalImg.width - marginX; cy = originalImg.height - marginY; break;
}
ctx.save();
ctx.translate(cx, cy);
const scale = size / 200; // Base drawing is scaled off a 200px height frame
ctx.scale(scale, scale);
ctx.translate(0, -100);
// Body
ctx.fillStyle = '#C21E56';
ctx.beginPath();
ctx.ellipse(0, 50, 40, 50, 0, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#222';
ctx.fillRect(-38, 55, 76, 8); // Belt
// Lapti (Bark Shoes)
ctx.fillStyle = '#D2B48C';
ctx.beginPath();
ctx.ellipse(-20, 100, 15, 10, 0, 0, Math.PI * 2);
ctx.ellipse(20, 100, 15, 10, 0, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = '#AA8050';
ctx.lineWidth = 2;
for (let j = -25; j <= -15; j += 3) { ctx.beginPath(); ctx.moveTo(j, 95); ctx.lineTo(j + 5, 105); ctx.stroke(); }
for (let j = 15; j <= 25; j += 3) { ctx.beginPath(); ctx.moveTo(j, 95); ctx.lineTo(j + 5, 105); ctx.stroke(); }
// Left Hand
ctx.fillStyle = '#E8B48F';
ctx.beginPath();
ctx.arc(-40, 50, 10, 0, Math.PI * 2);
ctx.fill();
// Broom
ctx.strokeStyle = '#8B5A2B';
ctx.lineWidth = 4;
ctx.beginPath();
ctx.moveTo(55, 80);
ctx.lineTo(20, -10);
ctx.stroke();
ctx.fillStyle = '#DEB887';
ctx.beginPath();
ctx.moveTo(55, 80);
ctx.lineTo(40, 100);
ctx.lineTo(70, 100);
ctx.fill();
// Right Hand (over broom)
ctx.fillStyle = '#E8B48F';
ctx.beginPath();
ctx.arc(40, 50, 10, 0, Math.PI * 2);
ctx.fill();
// Thick Beard
ctx.fillStyle = '#5C4033';
ctx.beginPath();
ctx.arc(0, 0, 45, 0, Math.PI);
ctx.quadraticCurveTo(50, 60, 0, 80);
ctx.quadraticCurveTo(-50, 60, -45, 0);
ctx.fill();
// Face
ctx.fillStyle = '#E8B48F';
ctx.beginPath();
ctx.ellipse(0, -10, 25, 25, 0, 0, Math.PI * 2);
ctx.fill();
// Eyes
ctx.fillStyle = 'white';
ctx.beginPath();
ctx.arc(-10, -15, 6, 0, Math.PI * 2);
ctx.arc(10, -15, 6, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = 'black';
ctx.beginPath();
ctx.arc(-10, -15, 3, 0, Math.PI * 2);
ctx.arc(10, -15, 3, 0, Math.PI * 2);
ctx.fill();
// Nose
ctx.fillStyle = '#D9A05B';
ctx.beginPath();
ctx.arc(0, -5, 7, 0, Math.PI * 2);
ctx.fill();
// Wild Hair
ctx.fillStyle = '#5C4033';
ctx.beginPath();
ctx.arc(0, -20, 35, Math.PI, Math.PI * 2);
ctx.fill();
ctx.beginPath(); ctx.arc(-25, -25, 15, 0, Math.PI * 2); ctx.fill();
ctx.beginPath(); ctx.arc(25, -25, 15, 0, Math.PI * 2); ctx.fill();
ctx.restore();
}
return canvas;
}
Apply Changes