Please bookmark this page to avoid losing your image tool!

Image Watermark Stain Filter Effect 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,
    watermarkText = "Watermark",
    fontSize = 40,
    fontFamily = "Impact",
    textColor = "rgba(0,0,0,0.25)",
    textAngle = -45,
    numBlotches = 10,
    blotchBaseColor = "180,140,80", // RGB components for stain color (e.g., yellowish-brown)
    blotchOpacity = 0.1,      // Base opacity for the core of stain circles (they fade to transparent)
    blotchSizeFactor = 0.15,  // Max radius of an individual circle component within a blotch, relative to min(image_width, image_height)
    agingIntensity = 0.3      // Image aging effect intensity (0=none, 1=full sepia-like)
) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const w = originalImg.width;
    const h = originalImg.height;
    canvas.width = w;
    canvas.height = h;

    // Helper to generate random number in a range
    const getRandom = (min, max) => Math.random() * (max - min) + min;

    // 1. Draw the original image onto the canvas
    ctx.drawImage(originalImg, 0, 0, w, h);

    // 2. Apply aging/sepia filter to the base image (if intensity > 0)
    // This gives the overall image an older look.
    if (agingIntensity > 0) {
        const imageData = ctx.getImageData(0, 0, w, h);
        const data = imageData.data;
        const intensity = Math.max(0, Math.min(1, agingIntensity)); // Clamp intensity to [0, 1]

        for (let i = 0; i < data.length; i += 4) {
            const r = data[i];
            const g = data[i + 1];
            const b = data[i + 2];

            // Standard sepia tone RGB calculation
            const sepiaR = Math.min(255, (r * 0.393) + (g * 0.769) + (b * 0.189));
            const sepiaG = Math.min(255, (r * 0.349) + (g * 0.686) + (b * 0.168));
            const sepiaB = Math.min(255, (r * 0.272) + (g * 0.534) + (b * 0.131));

            // Blend original pixel color with sepia color based on intensity
            data[i]   = r * (1 - intensity) + sepiaR * intensity;
            data[i+1] = g * (1 - intensity) + sepiaG * intensity;
            data[i+2] = b * (1 - intensity) + sepiaB * intensity;
            // Alpha channel (data[i+3]) remains unchanged
        }
        ctx.putImageData(imageData, 0, 0);
    }

    // 3. Apply Stains (Blotches)
    // Each "blotch" is a cluster of several semi-transparent, fading circles.
    const maxRadiusPerCircleComponent = Math.min(w, h) * blotchSizeFactor;

    for (let i = 0; i < numBlotches; i++) {
        // Determine the center point for this blotch cluster
        const blotchRootX = getRandom(0, w);
        const blotchRootY = getRandom(0, h);
        
        // Number of individual circles that make up this one blotch
        const numCirclesInBlotch = Math.floor(getRandom(3, 8));
        // Factor to control how spread out the circles in a single blotch are
        const blotchSpreadFactor = getRandom(0.5, 1.5); 

        for (let j = 0; j < numCirclesInBlotch; j++) {
            // Radius for this individual circle component
            const radius = getRandom(maxRadiusPerCircleComponent * 0.2, maxRadiusPerCircleComponent);
            
            // Random angle and distance from the blotchRoot to position this circle component
            const angle = getRandom(0, 2 * Math.PI);
            // Max distance of a component circle's center from the blotchRoot.
            // This defines the "spread" of the blotch.
            const distanceFromRoot = getRandom(0, maxRadiusPerCircleComponent * blotchSpreadFactor * 0.5); 
            const circleX = blotchRootX + Math.cos(angle) * distanceFromRoot;
            const circleY = blotchRootY + Math.sin(angle) * distanceFromRoot;
            
            // Slightly vary the opacity for each circle component for a more natural look
            const currentCircleOpacity = Math.max(0.01, Math.min(1, blotchOpacity * getRandom(0.7, 1.5)));
            
            // Create a radial gradient for the stain: solid color in center, fading to transparent at edges
            const grad = ctx.createRadialGradient(circleX, circleY, radius * 0.3, circleX, circleY, radius);
            grad.addColorStop(0, `rgba(${blotchBaseColor}, ${currentCircleOpacity})`);
            grad.addColorStop(1, `rgba(${blotchBaseColor}, 0)`); // Fade to fully transparent
            ctx.fillStyle = grad;
            
            // Draw the circle component
            ctx.beginPath();
            ctx.arc(circleX, circleY, radius, 0, 2 * Math.PI);
            ctx.fill();
        }
    }

    // 4. Apply Watermark Text
    if (watermarkText && watermarkText.trim() !== "") {
        ctx.save(); // Save current canvas state (transformations, styles)

        // Position text in the center of the image
        const textCenterX = w / 2;
        const textCenterY = h / 2;

        ctx.translate(textCenterX, textCenterY); // Move origin to canvas center
        ctx.rotate(textAngle * Math.PI / 180);   // Rotate canvas for angled text
        
        // Set font properties
        // Note: If `fontFamily` includes spaces or needs specific quoting (e.g., "'My Font', serif"),
        // ensure the `fontFamily` string is correctly formatted.
        ctx.font = `${fontSize}px ${fontFamily}`; 
        ctx.fillStyle = textColor;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';

        // Draw the watermark text at the (now) origin (0,0), which is the rotated center of the canvas
        ctx.fillText(watermarkText, 0, 0);

        ctx.restore(); // Restore canvas state to before text drawing
    }

    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 Image Watermark Stain Filter Effect Tool allows users to enhance their images by applying a customizable watermark, adding stain effects, and creating an aged appearance. This tool is ideal for photographers, graphic designers, and content creators looking to protect their images with text overlays while also giving their visuals a unique vintage feel with stain blotches. Use cases include adding personalized watermarks for branding, enhancing art photos, or creating nostalgic visuals for social media and marketing materials.

Leave a Reply

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