You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(
originalImg,
style = 'pop-art',
decoration = 'paw-prints',
petName = 'Fluffy',
themeColor = '#FF4081'
) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Cap the dimensions to prevent performance issues with large images
const MAX_DIM = 1500;
let cw = originalImg.width;
let ch = originalImg.height;
if (cw > MAX_DIM || ch > MAX_DIM) {
const ratio = Math.min(MAX_DIM / cw, MAX_DIM / ch);
cw = Math.round(cw * ratio);
ch = Math.round(ch * ratio);
}
canvas.width = cw;
canvas.height = ch;
// Helper functions for custom stylized effects and drawings
const drawPopArtQuadrant = (img, x, y, w, h, overlayColor) => {
ctx.save();
ctx.filter = 'contrast(1.5) grayscale(1)';
ctx.drawImage(img, 0, 0, originalImg.width, originalImg.height, x, y, w, h);
ctx.filter = 'none';
ctx.globalCompositeOperation = 'hard-light';
ctx.fillStyle = overlayColor;
ctx.globalAlpha = 0.7;
ctx.fillRect(x, y, w, h);
ctx.restore();
};
const drawPaw = (x, y, size, angle, color) => {
ctx.save();
ctx.translate(x, y);
ctx.rotate(angle);
ctx.fillStyle = color;
ctx.beginPath();
ctx.ellipse(0, size * 0.1, size * 0.4, size * 0.35, 0, 0, Math.PI * 2);
ctx.fill();
const toeAngles = [-1.1, -0.35, 0.35, 1.1];
const toeRadii = [0.15, 0.18, 0.18, 0.15];
const toeDist = size * 0.55;
for (let i = 0; i < toeAngles.length; i++) {
ctx.beginPath();
const tx = Math.cos(toeAngles[i] - Math.PI/2) * toeDist;
const ty = Math.sin(toeAngles[i] - Math.PI/2) * toeDist;
ctx.arc(tx, ty, size * toeRadii[i], 0, Math.PI * 2);
ctx.fill();
}
ctx.restore();
};
const drawStar = (x, y, size, color) => {
ctx.save();
ctx.translate(x, y);
ctx.fillStyle = color;
ctx.beginPath();
for(let i = 0; i < 8; i++) {
const radius = (i % 2 === 0) ? size * 0.8 : size * 0.3;
const angle = (i * Math.PI) / 4;
ctx.lineTo(Math.cos(angle) * radius, Math.sin(angle) * radius);
}
ctx.closePath();
ctx.fill();
ctx.restore();
};
const drawHeart = (x, y, size, color) => {
ctx.save();
// Shift a bit up so it visually centers better
ctx.translate(x, y - size/4);
ctx.scale(size/25, size/25);
ctx.fillStyle = color;
ctx.beginPath();
ctx.moveTo(0, 5);
ctx.bezierCurveTo(0, -5, -10, -5, -10, -5);
ctx.bezierCurveTo(-20, -5, -20, 10, -20, 10);
ctx.bezierCurveTo(-20, 20, 0, 30, 0, 35);
ctx.bezierCurveTo(0, 30, 20, 20, 20, 10);
ctx.bezierCurveTo(20, 10, 20, -5, 10, -5);
ctx.bezierCurveTo(10, -5, 0, -5, 0, 5);
ctx.fill();
ctx.restore();
};
// Apply main style
switch (style.toLowerCase()) {
case 'pop-art':
const hw = cw / 2;
const hh = ch / 2;
// Draw Andy Warhol style 4-quadrants
drawPopArtQuadrant(originalImg, 0, 0, hw, hh, '#00FFFF'); // Cyan
drawPopArtQuadrant(originalImg, hw, 0, hw, hh, '#FF00FF'); // Magenta
drawPopArtQuadrant(originalImg, 0, hh, hw, hh, '#FFFF00'); // Yellow
drawPopArtQuadrant(originalImg, hw, hh, hw, hh, '#00FF00'); // Lime
// Draw pop-art borders
ctx.lineWidth = Math.max(4, cw * 0.015);
ctx.strokeStyle = '#000000';
ctx.beginPath();
ctx.moveTo(hw, 0); ctx.lineTo(hw, ch);
ctx.moveTo(0, hh); ctx.lineTo(cw, hh);
ctx.stroke();
break;
case 'glamour':
ctx.filter = 'contrast(1.1) brightness(1.1)';
ctx.drawImage(originalImg, 0, 0, cw, ch);
// Soft glowing skin/fur
ctx.globalCompositeOperation = 'screen';
ctx.globalAlpha = 0.35;
ctx.filter = `blur(${Math.max(5, cw*0.015)}px) brightness(1.2)`;
ctx.drawImage(originalImg, 0, 0, cw, ch);
// Rosy warm glamour tint
ctx.globalCompositeOperation = 'overlay';
ctx.globalAlpha = 0.25;
ctx.fillStyle = '#ffb6c1';
ctx.fillRect(0, 0, cw, ch);
// Glamour Vignette
ctx.globalCompositeOperation = 'source-over';
ctx.globalAlpha = 1.0;
ctx.filter = 'none';
const glamGrad = ctx.createRadialGradient(cw/2, ch/2, Math.min(cw, ch)*0.3, cw/2, ch/2, Math.min(cw, ch)*0.8);
glamGrad.addColorStop(0, 'rgba(0,0,0,0)');
glamGrad.addColorStop(1, 'rgba(0,0,0,0.4)');
ctx.fillStyle = glamGrad;
ctx.fillRect(0, 0, cw, ch);
break;
case 'cartoon':
ctx.filter = 'saturate(1.5) contrast(1.3) brightness(1.05)';
ctx.drawImage(originalImg, 0, 0, cw, ch);
ctx.filter = 'none';
// Slight posterization effect to mimic flat cartoon shaded colors
try {
const imgData = ctx.getImageData(0, 0, cw, ch);
const data = imgData.data;
const factor = 256 / 6; // Color steps
for (let i = 0; i < data.length; i += 4) {
data[i] = Math.floor(data[i] / factor) * factor + (factor/2);
data[i+1] = Math.floor(data[i+1] / factor) * factor + (factor/2);
data[i+2] = Math.floor(data[i+2] / factor) * factor + (factor/2);
}
ctx.putImageData(imgData, 0, 0);
} catch(e) {
console.warn('Canvas tainted (CORS), simplified cartoon fallback applied.');
}
// Comic edge outline
ctx.lineWidth = Math.max(10, cw * 0.03);
ctx.strokeStyle = '#222';
ctx.strokeRect(0, 0, cw, ch);
break;
case 'vintage':
ctx.filter = 'sepia(0.85) contrast(1.2) brightness(0.95)';
ctx.drawImage(originalImg, 0, 0, cw, ch);
ctx.filter = 'none';
// Vintage brownish vignette
const vintageGrad = ctx.createRadialGradient(cw/2, ch/2, Math.min(cw, ch)*0.2, cw/2, ch/2, Math.min(cw, ch)*0.9);
vintageGrad.addColorStop(0, 'rgba(80, 50, 20, 0)');
vintageGrad.addColorStop(1, 'rgba(40, 20, 5, 0.7)');
ctx.fillStyle = vintageGrad;
ctx.fillRect(0, 0, cw, ch);
break;
case 'vibrant':
default:
ctx.filter = 'saturate(2.2) contrast(1.1) brightness(1.1)';
ctx.drawImage(originalImg, 0, 0, cw, ch);
ctx.filter = 'none';
break;
}
// Add Decorations around edges
if (decoration && decoration.toLowerCase() !== 'none') {
const decSize = Math.min(cw, ch) * 0.06;
const positions = [
{ rx: 0.1, ry: 0.1, angle: -0.4 },
{ rx: 0.9, ry: 0.1, angle: 0.4 },
{ rx: 0.12, ry: 0.5, angle: -0.7 },
{ rx: 0.88, ry: 0.5, angle: 0.7 },
{ rx: 0.15, ry: 0.8, angle: -0.2 },
{ rx: 0.85, ry: 0.8, angle: 0.2 }
];
ctx.shadowColor = 'rgba(0,0,0,0.4)';
ctx.shadowBlur = 8;
positions.forEach(pos => {
const dx = pos.rx * cw;
const dy = pos.ry * ch;
if (decoration === 'paw-prints') drawPaw(dx, dy, decSize, pos.angle, themeColor);
else if (decoration === 'stars') drawStar(dx, dy, decSize, themeColor);
else if (decoration === 'hearts') drawHeart(dx, dy, decSize, themeColor);
});
ctx.shadowColor = 'transparent'; // reset
}
// Makeover Pet Name Banner
if (petName && petName.trim() !== '') {
const labelHeight = Math.max(50, ch * 0.12);
const fontHeight = labelHeight * 0.55;
ctx.font = `bold ${fontHeight}px 'Comic Sans MS', 'Chalkboard SE', cursive, sans-serif`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const rawWidth = ctx.measureText(petName).width;
const textWidth = rawWidth + Math.max(60, cw * 0.1);
const bannerY = ch - labelHeight - Math.max(15, ch * 0.04);
const bannerX = (cw - textWidth) / 2;
ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
ctx.shadowColor = 'rgba(0,0,0,0.5)';
ctx.shadowBlur = 12;
ctx.shadowOffsetY = 6;
const drawRoundedRect = (bx, by, bw, bh, br) => {
if (ctx.roundRect) {
ctx.beginPath();
ctx.roundRect(bx, by, bw, bh, br);
} else {
ctx.beginPath();
ctx.moveTo(bx + br, by);
ctx.lineTo(bx + bw - br, by);
ctx.quadraticCurveTo(bx + bw, by, bx + bw, by + br);
ctx.lineTo(bx + bw, by + bh - br);
ctx.quadraticCurveTo(bx + bw, by + bh, bx + bw - br, by + bh);
ctx.lineTo(bx + br, by + bh);
ctx.quadraticCurveTo(bx, by + bh, bx, by + bh - br);
ctx.lineTo(bx, by + br);
ctx.quadraticCurveTo(bx, by, bx + br, by);
ctx.closePath();
}
};
// Render banner base
drawRoundedRect(bannerX, bannerY, textWidth, labelHeight, labelHeight / 2);
ctx.fill();
// Remove shadow to prevent doubled glow rings on stoke or text
ctx.shadowColor = 'transparent';
ctx.shadowBlur = 0;
ctx.shadowOffsetY = 0;
// Render inner border line
ctx.strokeStyle = themeColor;
ctx.lineWidth = Math.max(3, labelHeight * 0.08);
drawRoundedRect(bannerX + 6, bannerY + 6, textWidth - 12, labelHeight - 12, (labelHeight - 12) / 2);
ctx.stroke();
// Render the pet name text inside the banner
ctx.fillStyle = '#222';
ctx.fillText(petName, cw / 2, bannerY + labelHeight / 2 + (fontHeight * 0.05));
}
return canvas;
}
Apply Changes