Please bookmark this page to avoid losing your image tool!

Custom Pet Photo Makeover Tool

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
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;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Custom Pet Photo Makeover Tool allows you to transform standard pet photographs into artistic and personalized keepsakes. Users can apply various visual styles, including pop-art, glamour, cartoon, vintage, or vibrant effects. Additionally, the tool enables customization through decorative overlays like paw prints, stars, or hearts in a chosen theme color, and features a personalized name banner to highlight your pet’s name. This tool is ideal for creating fun social media posts, customized digital gifts, or unique pet portraits.

Leave a Reply

Your email address will not be published. Required fields are marked *