Please bookmark this page to avoid losing your image tool!

Image Spray Paint Mural Creator

(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,
    particleDensity = 20,
    particleSize = 8,
    sizeVariation = 0.7,
    jitterAmount = 5,
    minOpacity = 0.1,
    maxOpacity = 0.6,
    backgroundColor = 'white'
) {
    // Sanitize and validate numeric parameters
    particleDensity = Number(particleDensity);
    if (isNaN(particleDensity) || particleDensity < 0) particleDensity = 20;

    particleSize = Number(particleSize);
    if (isNaN(particleSize) || particleSize <= 0) particleSize = 8;

    sizeVariation = Number(sizeVariation);
    if (isNaN(sizeVariation) || sizeVariation < 0 || sizeVariation > 1) sizeVariation = 0.7;

    jitterAmount = Number(jitterAmount);
    if (isNaN(jitterAmount) || jitterAmount < 0) jitterAmount = 5;

    minOpacity = Number(minOpacity);
    if (isNaN(minOpacity) || minOpacity < 0 || minOpacity > 1) minOpacity = 0.1;

    maxOpacity = Number(maxOpacity);
    if (isNaN(maxOpacity) || maxOpacity < 0 || maxOpacity > 1) maxOpacity = 0.6;

    if (minOpacity > maxOpacity) {
        // Swap if minOpacity is greater than maxOpacity
        [minOpacity, maxOpacity] = [maxOpacity, minOpacity];
    }

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    // Use naturalWidth/Height for actual image dimensions, fallback to width/height
    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;

    // Handle cases where the image might not be loaded or has no dimensions
    if (imgWidth === 0 || imgHeight === 0) {
        console.warn("Original image has zero dimensions. Ensure it's loaded before calling processImage.");
        // Create a small placeholder canvas with an error message
        canvas.width = 200;
        canvas.height = 100;
        ctx.fillStyle = '#f0f0f0'; // Light gray background for the error message canvas
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = 'red';
        ctx.font = '12px Arial';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText('Error: Image not loaded or zero dimensions.', canvas.width / 2, canvas.height / 2);
        return canvas;
    }

    canvas.width = imgWidth;
    canvas.height = imgHeight;

    // Set background color if specified and not transparent
    // 'transparent' is a valid CSS color that makes the canvas transparent.
    // An empty string or null for backgroundColor will also result in a transparent background.
    if (backgroundColor && typeof backgroundColor === 'string' && backgroundColor.trim() !== '') {
        ctx.fillStyle = backgroundColor;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
    }

    // Draw the original image onto a temporary canvas to access its pixel data.
    // This is a common practice to avoid issues with directly reading from an Image object
    // and necessary to handle potential CORS tainting if the image is cross-origin.
    const tempCanvas = document.createElement('canvas');
    const tempCtx = tempCanvas.getContext('2d');
    tempCanvas.width = imgWidth;
    tempCanvas.height = imgHeight;
    
    let imageData;
    try {
        tempCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
        imageData = tempCtx.getImageData(0, 0, imgWidth, imgHeight);
    } catch (e) {
        console.error("Error getting image data:", e);
        // Draw an error message on the main canvas if pixel data cannot be accessed
        // (e.g., due to CORS restrictions on a tainted canvas)
        ctx.fillStyle = 'rgba(230, 230, 230, 0.8)'; // Overwrite with light error background
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = 'darkred';
        ctx.font = '16px Arial';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        const errorLines = [`Error: Could not process image data.`];
        if (e.name === 'SecurityError') {
            errorLines.push(`(This might be a CORS issue if the image is from another domain).`);
        }
        errorLines.forEach((line, index) => {
            ctx.fillText(line, canvas.width / 2, canvas.height / 2 - (10 * (errorLines.length-1)/2) + (index * 20) );
        });
        return canvas;
    }
    const data = imageData.data;

    // Calculate the total number of particles to draw.
    // particleDensity defines how many particles per 1000 pixels of image area.
    const numParticles = Math.floor((imgWidth * imgHeight / 1000) * particleDensity);

    // Drawing loop for each particle
    for (let i = 0; i < numParticles; i++) {
        // Pick a random x, y coordinate from the original image to sample its color
        const sx = Math.floor(Math.random() * imgWidth);
        const sy = Math.floor(Math.random() * imgHeight);

        // Calculate the index for the pixel data array
        const pixelIndex = (sy * imgWidth + sx) * 4;
        const r = data[pixelIndex];
        const g = data[pixelIndex + 1];
        const b = data[pixelIndex + 2];
        // const originalAlpha = data[pixelIndex + 3]; // Original alpha, could be used if needed

        // If pixel data components are undefined (should not happen for valid sx, sy), skip this particle
        if (typeof r === 'undefined' || typeof g === 'undefined' || typeof b === 'undefined') {
            continue;
        }
        
        // Calculate properties for the current particle
        // particleSize is the average radius
        const currentRadius = Math.max(0.5, particleSize * (1 + (Math.random() - 0.5) * 2 * sizeVariation));
        const currentOpacity = minOpacity + Math.random() * (maxOpacity - minOpacity);

        // Determine the actual drawing position, adding jitter to the sampled position
        const drawX = sx + (Math.random() - 0.5) * 2 * jitterAmount;
        const drawY = sy + (Math.random() - 0.5) * 2 * jitterAmount;

        // Set fill style with sampled color and calculated opacity
        ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${currentOpacity})`;
        
        // Draw the particle (a circle)
        ctx.beginPath();
        ctx.arc(drawX, drawY, currentRadius, 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 Spray Paint Mural Creator tool allows users to transform their images into a unique spray paint mural effect. By adjusting parameters like particle density, size, and opacity, users can create visually striking artistic renditions of their images. This tool is particularly useful for artists and designers looking to add a creative touch to photos, making it suitable for digital art projects, social media posts, decor designs, or any application where an artistic visual interpretation is desired.

Leave a Reply

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