Please bookmark this page to avoid losing your image tool!

Image Of A Grandmother

(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.
function processImage(originalImg, effectMode = "cross-stitch", parameterValue = "12") {
    // This utility provides three interpretations of an "Image of a Grandmother" (Бабушка) filter:
    // 1. "cross-stitch" (default): Converts the image into a grandmother's cross-stitch artwork.
    // 2. "babushka": Overlays a traditional red floral babushka headscarf framing the main subject.
    // 3. "vintage": Applies an old photograph sepia filter with a heavy vignette and film noise.
    
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const width = originalImg.width;
    const height = originalImg.height;
    canvas.width = width;
    canvas.height = height;

    const mode = effectMode.toLowerCase();

    if (mode === "vintage") {
        // Appy an old vintage photograph style
        ctx.drawImage(originalImg, 0, 0, width, height);
        const imgData = ctx.getImageData(0, 0, width, height);
        const data = imgData.data;

        // Sepia & Noise adjustments
        for (let i = 0; i < data.length; i += 4) {
            let r = data[i];
            let g = data[i+1];
            let b = data[i+2];

            // Sepia Matrix calculations
            let tr = r * 0.393 + g * 0.769 + b * 0.189;
            let tg = r * 0.349 + g * 0.686 + b * 0.168;
            let tb = r * 0.272 + g * 0.534 + b * 0.131;

            // Reduce contrast & add random aged film noise
            let noise = Math.random() * 20 - 10;
            data[i] = Math.min(255, tr * 0.95 + noise);
            data[i+1] = Math.min(255, tg * 0.95 + noise);
            data[i+2] = Math.min(255, tb * 0.95 + noise);
        }
        ctx.putImageData(imgData, 0, 0);

        // Add typical Grandmother Photo Frame vignette overlay
        const grad = ctx.createRadialGradient(
            width/2, height/2, Math.min(width, height) * 0.4, 
            width/2, height/2, Math.max(width, height) * 0.75
        );
        grad.addColorStop(0, 'rgba(0, 0, 0, 0)');
        grad.addColorStop(1, 'rgba(50, 20, 0, 0.85)');
        ctx.fillStyle = grad;
        ctx.fillRect(0, 0, width, height);

        return canvas;
    } 
    else if (mode === "babushka") {
        // Wraps the main target inside a traditional Babushka headscarf overlay
        ctx.drawImage(originalImg, 0, 0, width, height);
        
        const size = Math.min(width, height);
        
        // Generate a classic red polka-dot/floral pattern programmatically
        const patCanvas = document.createElement('canvas');
        patCanvas.width = 40; 
        patCanvas.height = 40;
        const pCtx = patCanvas.getContext('2d');
        pCtx.fillStyle = '#b01020';
        pCtx.fillRect(0, 0, 40, 40);
        
        pCtx.fillStyle = '#ffffff';
        pCtx.beginPath();
        pCtx.arc(10, 10, 6, 0, Math.PI*2);
        pCtx.arc(30, 30, 6, 0, Math.PI*2);
        pCtx.fill();
        
        pCtx.fillStyle = '#ffcc00';
        pCtx.beginPath();
        pCtx.arc(10, 10, 2.5, 0, Math.PI*2);
        pCtx.arc(30, 30, 2.5, 0, Math.PI*2);
        pCtx.fill();
        const scarfPat = ctx.createPattern(patCanvas, 'repeat');

        // Target face/subject area
        const cx = width / 2;
        const cy = height / 2.3;
        const rx = size * 0.28;
        const ry = size * 0.36;

        ctx.save();
        ctx.shadowColor = 'rgba(0,0,0,0.8)';
        ctx.shadowBlur = size * 0.05;
        ctx.shadowOffsetY = size * 0.02;

        // Draw scarf plane with inverse face cutout
        ctx.beginPath();
        ctx.rect(-width, -height, width * 3, height * 3);
        ctx.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2, true);
        ctx.fillStyle = scarfPat;
        ctx.fill();
        
        // Draw the bottom knot of the headscarf
        const knotY = cy + ry + size * 0.03;
        ctx.beginPath();
        ctx.arc(cx, knotY, size * 0.07, 0, Math.PI * 2);
        ctx.fill();
        
        // Scarf tails falling off the knot
        ctx.beginPath();
        ctx.moveTo(cx, knotY);
        ctx.lineTo(cx - size * 0.12, knotY + size * 0.2);
        ctx.lineTo(cx - size * 0.03, knotY + size * 0.25);
        ctx.closePath();
        ctx.fill();
        
        ctx.beginPath();
        ctx.moveTo(cx, knotY);
        ctx.lineTo(cx + size * 0.12, knotY + size * 0.2);
        ctx.lineTo(cx + size * 0.03, knotY + size * 0.25);
        ctx.closePath();
        ctx.fill();
        
        ctx.restore();

        return canvas;
    }
    else {
        // Cross-Stitch Mode (Default Image Converter operation)
        // Convert the image into a Grandmother's Needlepoint / Cross-Stitch Artwork 
        const stitchSize = Math.max(4, parseInt(parameterValue) || 12);
        
        // Render Aida cloth fabric background
        ctx.fillStyle = "#f4f1ea";
        ctx.fillRect(0, 0, width, height);

        // Draw Aida fabric punch holes
        ctx.fillStyle = "#e0dbce";
        for (let y = 0; y <= height; y += stitchSize) {
            for (let x = 0; x <= width; x += stitchSize) {
                ctx.beginPath();
                ctx.arc(x, y, stitchSize * 0.12, 0, Math.PI * 2);
                ctx.fill();
            }
        }

        const cols = Math.floor(width / stitchSize);
        const rows = Math.floor(height / stitchSize);
        
        // Downsample image for cross-stitch color extraction
        const offCanvas = document.createElement('canvas');
        offCanvas.width = cols;
        offCanvas.height = rows;
        const offCtx = offCanvas.getContext('2d');
        offCtx.drawImage(originalImg, 0, 0, cols, rows);
        
        const imgData = offCtx.getImageData(0, 0, cols, rows).data;

        ctx.lineCap = 'round';
        ctx.lineJoin = 'round';

        // Draw individual cross stitches
        for (let y = 0; y < rows; y++) {
            for (let x = 0; x < cols; x++) {
                const i = (y * cols + x) * 4;
                const r = imgData[i];
                const g = imgData[i+1];
                const b = imgData[i+2];
                const a = imgData[i+3];

                if (a < 50) continue; 
                // Skip stark white pieces to let fabric naturally act as negative space
                if (r > 240 && g > 240 && b > 240) continue;

                const cx = x * stitchSize + stitchSize / 2;
                const cy = y * stitchSize + stitchSize / 2;
                const offset = stitchSize * 0.35;

                // Stitch dropped shadow 
                ctx.strokeStyle = `rgba(0, 0, 0, 0.25)`;
                ctx.lineWidth = Math.max(1, stitchSize * 0.4);
                ctx.beginPath();
                ctx.moveTo(cx - offset, cy - offset + 1.5);
                ctx.lineTo(cx + offset, cy + offset + 1.5);
                ctx.stroke();

                const color = `rgb(${r}, ${g}, ${b})`;

                // Thread passing beneath (bottom stitch)
                ctx.strokeStyle = color;
                ctx.lineWidth = Math.max(1, stitchSize * 0.35);
                ctx.beginPath();
                ctx.moveTo(cx - offset, cy + offset);
                ctx.lineTo(cx + offset, cy - offset);
                ctx.stroke();

                // Thread passing over (top stitch)
                ctx.beginPath();
                ctx.moveTo(cx - offset, cy - offset);
                ctx.lineTo(cx + offset, cy + offset);
                ctx.stroke();
                
                // Outer texture highlight on the crest of the top thread
                ctx.strokeStyle = `rgba(255, 255, 255, 0.2)`;
                ctx.lineWidth = Math.max(1, stitchSize * 0.1);
                ctx.beginPath();
                ctx.moveTo(cx - offset * 0.6, cy - offset * 0.6);
                ctx.lineTo(cx + offset * 0.6, cy + offset * 0.6);
                ctx.stroke();
            }
        }

        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

This image utility tool applies various stylized filters to your photos to create unique, themed artwork. Users can transform their images into intricate cross-stitch or needlepoint embroidery designs, overlay a traditional floral headscarf pattern onto subjects, or apply a vintage sepia filter with film noise and a classic vignette for an aged photograph look. It is ideal for creating personalized digital crafts, nostalgic social media posts, or themed artistic portraits.

Leave a Reply

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