Please bookmark this page to avoid losing your image tool!

Image Splatter Paint 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.
function processImage(
    originalImg,
    numSplatterClusters = 50,
    dotsPerClusterMin = 10,
    dotsPerClusterMax = 50,
    clusterSpreadRadius = 30,
    dotRadiusMin = 1,
    dotRadiusMax = 3,
    dotOpacity = 0.8, // Range: 0.0 to 1.0
    colorSource = "image", // Options: "image", "random", or a CSS color string (e.g., "red", "#FF0000")
    colorVariation = 20  // Range: 0 to 255. Max R,G,B deviation for dots from their cluster's base color.
) {
    // Ensure numeric parameters are valid numbers and within sensible ranges
    numSplatterClusters = Math.max(0, Number(numSplatterClusters));
    dotsPerClusterMin = Math.max(0, Number(dotsPerClusterMin));
    // Ensure dotsPerClusterMax is not less than dotsPerClusterMin
    dotsPerClusterMax = Math.max(dotsPerClusterMin, Number(dotsPerClusterMax));
    clusterSpreadRadius = Math.max(0, Number(clusterSpreadRadius));
    // Ensure dotRadiusMin is at least a small positive value for visibility
    dotRadiusMin = Math.max(0.1, Number(dotRadiusMin));
    // Ensure dotRadiusMax is not less than dotRadiusMin
    dotRadiusMax = Math.max(dotRadiusMin, Number(dotRadiusMax));
    dotOpacity = Math.max(0, Math.min(1, Number(dotOpacity)));
    colorVariation = Math.max(0, Math.min(255, Number(colorVariation)));

    const canvas = document.createElement('canvas');
    
    // Robustness check for the input image
    if (!originalImg || !(originalImg instanceof HTMLImageElement) || !originalImg.complete || originalImg.naturalWidth === 0 || originalImg.naturalHeight === 0) {
        console.error("Image Splatter Paint: Invalid or unloaded image provided. Returning a placeholder canvas.");
        // Fallback canvas size if image details are unavailable
        canvas.width = (originalImg && originalImg.width > 0) ? originalImg.width : 300;
        canvas.height = (originalImg && originalImg.height > 0) ? originalImg.height : 150;
        const errorCtx = canvas.getContext('2d');
        errorCtx.fillStyle = 'lightgray';
        errorCtx.fillRect(0, 0, canvas.width, canvas.height);
        errorCtx.fillStyle = 'black';
        errorCtx.font = '16px Arial';
        errorCtx.textAlign = 'center';
        errorCtx.textBaseline = 'middle';
        errorCtx.fillText('Invalid Image', canvas.width / 2, canvas.height / 2);
        return canvas;
    }
    
    canvas.width = originalImg.naturalWidth;
    canvas.height = originalImg.naturalHeight;
    
    // Use { willReadFrequently: true } if image data sampling is frequent or on large images.
    // For "image" colorSource, we read pixel data.
    const ctxOptions = (colorSource === "image") ? { willReadFrequently: true } : {};
    const ctx = canvas.getContext('2d', ctxOptions);

    // Helper function to clamp a value between a min and max
    function clamp(value, min, max) {
        return Math.max(min, Math.min(value, max));
    }

    // Helper function to parse a CSS color string (e.g., "red", "#FF0000") into an {r, g, b} object.
    function parseColor(colorString) {
        const tempCanvas = document.createElement('canvas');
        tempCanvas.width = 1;
        tempCanvas.height = 1;
        const tempCtx = tempCanvas.getContext('2d'); // No need for willReadFrequently for 1x1
        tempCtx.fillStyle = colorString;
        tempCtx.fillRect(0, 0, 1, 1);
        const data = tempCtx.getImageData(0, 0, 1, 1).data;
        return { r: data[0], g: data[1], b: data[2] };
    }

    // Draw the original image onto the canvas to serve as the background
    ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);

    let originalImageData = null;
    if (colorSource === "image") {
        try {
            originalImageData = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
        } catch (e) {
            console.error("Image Splatter Paint: Could not get image data (e.g., canvas tainted). Defaulting colorSource to 'random'.", e);
            colorSource = "random"; // Fallback if getImageData fails
        }
    }
    
    let parsedFixedColor = null;
    if (colorSource !== "image" && colorSource !== "random") {
        try {
            parsedFixedColor = parseColor(colorSource);
        } catch (e) {
            console.error(`Image Splatter Paint: Invalid colorSource string '${colorSource}'. Defaulting to 'random'.`, e);
            colorSource = "random"; // Fallback for invalid color string
            parsedFixedColor = null; // Ensure it's null if fallback occurs
        }
    }

    for (let i = 0; i < numSplatterClusters; i++) {
        // Determine the center of the current splatter cluster
        const clusterCenterX = Math.random() * canvas.width;
        const clusterCenterY = Math.random() * canvas.height;

        let baseR, baseG, baseB; // Base color for the current cluster

        if (colorSource === "image" && originalImageData) {
            const x = clamp(Math.floor(clusterCenterX), 0, canvas.width - 1);
            const y = clamp(Math.floor(clusterCenterY), 0, canvas.height - 1);
            const pixelIndex = (y * canvas.width + x) * 4;
            baseR = originalImageData[pixelIndex];
            baseG = originalImageData[pixelIndex + 1];
            baseB = originalImageData[pixelIndex + 2];
        } else if (colorSource === "random" || (colorSource === "image" && !originalImageData) ) { // Fallback for "image" if data is null
            baseR = Math.floor(Math.random() * 256);
            baseG = Math.floor(Math.random() * 256);
            baseB = Math.floor(Math.random() * 256);
        } else { // Fixed color source
            if(parsedFixedColor){
                baseR = parsedFixedColor.r;
                baseG = parsedFixedColor.g;
                baseB = parsedFixedColor.b;
            } else { // Should not be reached if fallbacks above are correct, but defensively:
                baseR = 0; baseG = 0; baseB = 0; // Default to black
            }
        }

        const numDotsInCluster = Math.floor(dotsPerClusterMin + Math.random() * (dotsPerClusterMax - dotsPerClusterMin + 1));

        for (let j = 0; j < numDotsInCluster; j++) {
            const angle = Math.random() * 2 * Math.PI;
            // Using Math.random() for distance skews dots towards the center (density decreases with radius)
            // For uniform area distribution, use: Math.sqrt(Math.random()) * clusterSpreadRadius
            const distanceFromCenter = Math.random() * clusterSpreadRadius; 
            
            const dotX = clusterCenterX + distanceFromCenter * Math.cos(angle);
            const dotY = clusterCenterY + distanceFromCenter * Math.sin(angle);

            const dotActualRadius = dotRadiusMin + Math.random() * (dotRadiusMax - dotRadiusMin);

            // Apply color variation to the base color of the cluster
            const r = clamp(Math.floor(baseR + (Math.random() - 0.5) * 2 * colorVariation), 0, 255);
            const g = clamp(Math.floor(baseG + (Math.random() - 0.5) * 2 * colorVariation), 0, 255);
            const b = clamp(Math.floor(baseB + (Math.random() - 0.5) * 2 * colorVariation), 0, 255);
            
            ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${dotOpacity})`;
            
            ctx.beginPath();
            ctx.arc(dotX, dotY, dotActualRadius, 0, 2 * Math.PI);
            ctx.fill();
        }
    }

    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 Splatter Paint Filter Effect Tool allows users to creatively transform their images into vibrant splatter art. By adjusting various parameters, users can control the number of colorful splatter clusters, the density of dots within those clusters, and the variation in color. This tool can be used for artistic effects in graphic design, social media content creation, or any project that requires a unique and playful visual style. Users can choose colors based on the original image or select random colors, making it versatile for different artistic needs.

Leave a Reply

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