Please bookmark this page to avoid losing your image tool!

Image Quantum Particle 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,
    particleCountArg = 5000,
    particleSizeMinArg = 1,
    particleSizeMaxArg = 5,
    brightnessThresholdArg = 0, // Expected range 0-255
    alphaFactorArg = 1.0,     // Multiplier for particle alpha
    positionJitterArg = 2,    // Max random offset for particle position in pixels
    backgroundColorArg = "black"  // Background color string (e.g., "black", "#FF0000", "rgba(0,0,0,0)")
) {
    // --- Parameter parsing and validation ---
    let numParticleCount = Number(particleCountArg);
    if (isNaN(numParticleCount) || numParticleCount < 0) {
        numParticleCount = 5000; // Default if NaN or negative
    }

    let numParticleSizeMin = Number(particleSizeMinArg);
    if (isNaN(numParticleSizeMin)) {
        numParticleSizeMin = 1; // Default if NaN
    }

    let numParticleSizeMax = Number(particleSizeMaxArg);
    if (isNaN(numParticleSizeMax)) {
        numParticleSizeMax = 5; // Default if NaN
    }
    
    // Ensure particle sizes are positive and min <= max
    numParticleSizeMin = Math.max(0.1, numParticleSizeMin); // Smallest drawable size
    numParticleSizeMax = Math.max(0.1, numParticleSizeMax);

    if (numParticleSizeMin > numParticleSizeMax) {
        [numParticleSizeMin, numParticleSizeMax] = [numParticleSizeMax, numParticleSizeMin]; // Swap
    }
    // Ensure max is at least min after potential individual adjustments
    if (numParticleSizeMax < numParticleSizeMin) {
         numParticleSizeMax = numParticleSizeMin;
    }


    let numBrightnessThreshold = Number(brightnessThresholdArg);
    if (isNaN(numBrightnessThreshold)) {
        numBrightnessThreshold = 0; // Default if NaN
    }
    numBrightnessThreshold = Math.max(0, Math.min(255, numBrightnessThreshold)); // Clamp to 0-255

    let numAlphaFactor = Number(alphaFactorArg);
    if (isNaN(numAlphaFactor)) {
        numAlphaFactor = 1.0; // Default if NaN
    }

    let numPositionJitter = Number(positionJitterArg);
    if (isNaN(numPositionJitter) || numPositionJitter < 0) {
        numPositionJitter = 2; // Default if NaN or negative
    }
    numPositionJitter = Math.max(0, numPositionJitter); // Ensure non-negative

    const backgroundColor = typeof backgroundColorArg === 'string' ? backgroundColorArg : "black";


    // --- Canvas setup ---
    const outputCanvas = document.createElement('canvas');
    const ctx = outputCanvas.getContext('2d');

    const imgWidth = originalImg.naturalWidth || originalImg.width;
    const imgHeight = originalImg.naturalHeight || originalImg.height;
    
    outputCanvas.width = imgWidth;
    outputCanvas.height = imgHeight;

    // If image dimensions are invalid, return early
    if (imgWidth <= 0 || imgHeight <= 0) {
        if (backgroundColor && backgroundColor.toLowerCase() !== "transparent") {
            try {
                ctx.fillStyle = backgroundColor;
                ctx.fillRect(0, 0, imgWidth, imgHeight);
            } catch(e) { /* ignore error for 0-dim canvas */ }
        }
        return outputCanvas; // Returns blank canvas
    }
    
    // Draw background color
    if (backgroundColor && backgroundColor.toLowerCase() !== "transparent") {
        ctx.fillStyle = backgroundColor;
        ctx.fillRect(0, 0, imgWidth, imgHeight);
    }

    // If no particles to draw, return canvas with just background
    if (numParticleCount <= 0) {
        return outputCanvas;
    }
    
    // --- Pixel data acquisition ---
    const offscreenCanvas = document.createElement('canvas');
    offscreenCanvas.width = imgWidth;
    offscreenCanvas.height = imgHeight;
    const offscreenCtx = offscreenCanvas.getContext('2d', { willReadFrequently: true }); 
    
    offscreenCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
    
    let imageData;
    try {
        imageData = offscreenCtx.getImageData(0, 0, imgWidth, imgHeight);
    } catch (e) {
        console.error("Error getting image data (CORS issue or invalid image source?):", e);
        // Fallback: draw original image onto output canvas if pixel processing fails
        ctx.drawImage(originalImg, 0, 0, imgWidth, imgHeight); // Overwrites background if it was set
        return outputCanvas;
    }
    const pixels = imageData.data;

    // --- Particle generation and drawing ---
    for (let i = 0; i < numParticleCount; i++) {
        // Pick a random source coordinate from the original image
        const sourceX = Math.random() * imgWidth;
        const sourceY = Math.random() * imgHeight;

        const floorSourceX = Math.floor(sourceX);
        const floorSourceY = Math.floor(sourceY);
        
        // Calculate index for the 1D pixel array
        const pixelIndex = (floorSourceY * imgWidth + floorSourceX) * 4;

        // Safety check for pixel array access, though generally Math.floor(Math.random()*dim) is safe
        if (pixelIndex < 0 || pixelIndex + 3 >= pixels.length) {
            continue;  // Should rarely happen with valid imgWidth/imgHeight
        }

        const r = pixels[pixelIndex];
        const g = pixels[pixelIndex + 1];
        const b = pixels[pixelIndex + 2];
        const a = pixels[pixelIndex + 3];

        // Calculate perceptual brightness (luminance)
        const brightness = (r * 0.299 + g * 0.587 + b * 0.114);

        if (brightness < numBrightnessThreshold) {
            continue; // Skip particle if source pixel is too dark
        }

        // Determine particle size (randomly within min/max range)
        const currentParticleSize = numParticleSizeMin + Math.random() * (numParticleSizeMax - numParticleSizeMin);
        
        // Skip if particle size is too small to draw (radius would be half of this)
        if (currentParticleSize < 0.1) { 
            continue;
        }

        // Determine particle alpha, modulated by alphaFactor
        const particleAlpha = (a / 255) * numAlphaFactor;
        
        // Skip if particle is effectively fully transparent
        if (particleAlpha <= 0.001) { // Use a small threshold to avoid drawing nearly invisible particles
            continue;
        }
        
        // Apply position jitter: random offset from source coordinate
        const drawX = sourceX + (Math.random() - 0.5) * 2 * numPositionJitter;
        const drawY = sourceY + (Math.random() - 0.5) * 2 * numPositionJitter;
        
        // Ensure alpha is clamped between 0 and 1 for canvas context
        ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${Math.min(1, Math.max(0, particleAlpha))})`;
        
        ctx.beginPath();
        // Radius must be positive for ctx.arc
        ctx.arc(drawX, drawY, currentParticleSize / 2, 0, 2 * Math.PI);
        ctx.fill();
    }

    return outputCanvas;
}

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 Quantum Particle Filter Effect Tool allows users to create a unique particle effect on images by simulating a distribution of particles based on pixel brightness and color. Users can specify parameters such as the number of particles, their size, and position randomness, as well as define a brightness threshold for particle visibility. This tool is ideal for graphic designers and artists looking to enhance images with artistic effects, create interesting backgrounds, or produce visuals for creative projects.

Leave a Reply

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