You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, dogSizeMultiplier = 0.6, positionX = "center", positionY = "bottom", discoMode = 1) {
// Validate and parse parameters
const multiplier = parseFloat(dogSizeMultiplier) || 0.6;
const disco = parseInt(discoMode, 10);
// Setup Canvas
const canvas = document.createElement("canvas");
const w = originalImg.naturalWidth || originalImg.width;
const h = originalImg.naturalHeight || originalImg.height;
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext("2d");
// 1. Draw the original background photo
ctx.drawImage(originalImg, 0, 0, w, h);
// 2. Add Disco / Dance Floor Effects if requested
if (disco === 1) {
// Festive gradient overlay
const shadowGrad = ctx.createLinearGradient(0, 0, w, h);
shadowGrad.addColorStop(0, "rgba(255, 0, 255, 0.2)");
shadowGrad.addColorStop(0.5, "rgba(0, 255, 255, 0.1)");
shadowGrad.addColorStop(1, "rgba(255, 255, 0, 0.2)");
ctx.fillStyle = shadowGrad;
ctx.fillRect(0, 0, w, h);
// Perspective Dance Floor grid at the bottom
ctx.save();
const floorTop = h * 0.65;
const floorHeight = h - floorTop;
ctx.beginPath();
ctx.rect(0, floorTop, w, floorHeight);
ctx.clip(); // Restrict floor texture to the bottom 35% of the image
// Horizontal grid lines shrinking toward horizon
ctx.beginPath();
for (let i = 0; i <= 10; i++) {
const percent = Math.pow(i / 10, 1.5);
const yOff = floorTop + floorHeight * percent;
ctx.moveTo(0, yOff);
ctx.lineTo(w, yOff);
}
// Vertical perspective lines
for (let j = -30; j <= 30; j++) {
const x0 = w / 2;
const y0 = floorTop;
const x1 = w / 2 + (w * 0.1 * j);
const y1 = h;
ctx.moveTo(x0, y0);
ctx.lineTo(x1, y1);
}
ctx.strokeStyle = "rgba(0, 255, 255, 0.4)";
ctx.lineWidth = Math.max(1, w * 0.005);
ctx.stroke();
ctx.restore();
// Random floating party lights
for(let i = 0; i < 20; i++) {
ctx.beginPath();
ctx.arc(
Math.random() * w,
Math.random() * h * 0.8, // keep them mostly off the very bottom edge
Math.random() * (w * 0.04) + 5,
0,
Math.PI * 2
);
ctx.fillStyle = `hsla(${Math.random() * 360}, 100%, 70%, 0.3)`;
ctx.fill();
}
}
// 3. Define Vector SVG for the "Dancing Dog"
// Using standard SVG vectors ensures the dog renders sharply and works entirely offline.
const svgStr = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="500" height="500">
<!-- Ground Shadow -->
<ellipse cx="50" cy="98" rx="20" ry="4" fill="rgba(0,0,0,0.3)"/>
<!-- Torso -->
<ellipse cx="50" cy="65" rx="16" ry="22" fill="#D2691E" transform="rotate(-15 50 65)"/>
<!-- Light Belly -->
<ellipse cx="48" cy="67" rx="10" ry="14" fill="#F4A460" transform="rotate(-15 48 67)"/>
<!-- Straight Leg -->
<line x1="45" y1="83" x2="35" y2="98" stroke="#D2691E" stroke-width="7" stroke-linecap="round"/>
<!-- Dancing Bent Knee Leg -->
<path d="M 55 85 L 68 83 L 65 96" stroke="#D2691E" stroke-width="7" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
<!-- Left Arm Raised High -->
<line x1="38" y1="55" x2="20" y2="40" stroke="#D2691E" stroke-width="6" stroke-linecap="round"/>
<!-- Right Arm Angled Down -->
<line x1="62" y1="60" x2="75" y2="75" stroke="#D2691E" stroke-width="6" stroke-linecap="round"/>
<!-- Head Base -->
<circle cx="45" cy="40" r="14" fill="#D2691E"/>
<ellipse cx="33" cy="43" rx="10" ry="7" fill="#F4A460"/>
<circle cx="25" cy="42" r="3" fill="black"/> <!-- Nose -->
<!-- Cool Sunglasses -->
<path d="M 32 34 Q 40 34 41 40 Q 36 42 32 40 Z" fill="black"/>
<path d="M 43 34 Q 50 34 51 40 Q 46 42 43 40 Z" fill="black"/>
<line x1="41" y1="36" x2="43" y2="36" stroke="black" stroke-width="2"/>
<line x1="51" y1="36" x2="57" y2="34" stroke="black" stroke-width="2"/>
<!-- Flipping Ears -->
<ellipse cx="54" cy="30" rx="5" ry="14" fill="#8B4513" transform="rotate(40 54 30)"/>
<ellipse cx="40" cy="27" rx="5" ry="12" fill="#8B4513" transform="rotate(-20 40 27)"/>
<!-- Wagging Tail -->
<path d="M 62 70 Q 85 60 75 45" stroke="#D2691E" stroke-width="6" stroke-linecap="round" fill="none"/>
<!-- Movement Lines -->
<path d="M 75 45 C 80 40, 90 45, 85 55" stroke="#8B4513" stroke-width="2" fill="none" opacity="0.6"/>
<path d="M 12 35 C 10 40, 15 50, 20 48" stroke="#8B4513" stroke-width="2" fill="none" opacity="0.6"/>
</svg>`;
const dogImg = new Image();
// encodeURIComponent is crucial so hash signs (#) inside the SVG string don't truncate the data URL.
const svgUrl = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svgStr);
await new Promise((resolve, reject) => {
dogImg.onload = resolve;
dogImg.onerror = reject;
dogImg.src = svgUrl;
});
// 4. Calculate Sizing & Positioning for the Dog Overlay
const dogSize = Math.max(w, h) * multiplier;
const dogWidth = dogSize;
const dogHeight = dogSize;
let poseX, poseY;
const pxCheck = positionX.toString().toLowerCase();
const pyCheck = positionY.toString().toLowerCase();
// Horizontal Position calculation
if (pxCheck === "left") poseX = w * 0.05;
else if (pxCheck === "right") poseX = w * 0.95 - dogWidth;
else if (pxCheck === "center") poseX = (w - dogWidth) / 2;
else poseX = parseFloat(positionX) || (w - dogWidth) / 2;
// Vertical Position calculation
if (pyCheck === "top") poseY = h * 0.05;
else if (pyCheck === "bottom") poseY = h * 0.98 - dogHeight;
else if (pyCheck === "center") poseY = (h - dogHeight) / 2;
else poseY = parseFloat(positionY) || (h - dogHeight);
// Draw the Dog
ctx.drawImage(dogImg, poseX, poseY, dogWidth, dogHeight);
// 5. Draw Emojis (Musical notes & sparkles) surrounding the Dog
const textSize = Math.max(20, dogSize * 0.15);
ctx.font = `${textSize}px Arial, sans-serif`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const emojis = ['🎵', '🎶', '✨', '🕺', '💫', '🪩', '🎶'];
for(let i = 0; i < 8; i++) {
// Semi-random scatter radiating out from the dog's center frame
const ex = poseX + dogWidth * (Math.random() * 1.4 - 0.2);
const ey = poseY + dogHeight * (Math.random() * 1.4 - 0.2);
// Prevent emojis from hiding the dog's face squarely
const dx = ex - (poseX + dogWidth / 2);
const dy = ey - (poseY + dogHeight / 2);
if (Math.abs(dx) < dogWidth * 0.3 && Math.abs(dy) < dogHeight * 0.3) {
continue;
}
ctx.save();
ctx.translate(ex, ey);
ctx.rotate((Math.random() - 0.5) * 0.8);
ctx.globalAlpha = 0.8 + Math.random() * 0.2;
// Visual contrast to ensure it pops out on any photo backdrop
ctx.shadowColor = 'rgba(0,0,0,0.7)';
ctx.shadowBlur = 6;
ctx.fillText(emojis[i % emojis.length], 0, 0);
ctx.restore();
}
return canvas;
}
Apply Changes