Please bookmark this page to avoid losing your image tool!

Image Voronoi Filter Application

(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, numSitesParam = 100, showSitesParam = "false", siteColorParam = "black", siteSizeParam = 2) {
    // Parameter parsing and validation
    let numSites;
    if (typeof numSitesParam === 'string') {
        numSites = parseInt(numSitesParam, 10);
    } else {
        numSites = numSitesParam; // Assumed to be a number as per guidelines
    }
    if (isNaN(numSites) || numSites <= 0) {
        numSites = 100; // Default if parsing failed or invalid value
    }

    const showSites = String(showSitesParam).toLowerCase() === 'true';
    
    let siteColor;
    if (typeof siteColorParam === 'number') {
        // Convert number to hex color string, e.g., 0xFF0000 -> "#ff0000"
        const hex = (siteColorParam & 0xFFFFFF).toString(16).padStart(6, '0');
        siteColor = `#${hex}`;
    } else {
        siteColor = String(siteColorParam); // Use as string (e.g., "red", "#FF0000")
    }
    
    let siteSize;
    if (typeof siteSizeParam === 'string') {
        siteSize = parseFloat(siteSizeParam);
    } else {
        siteSize = siteSizeParam; // Assumed to be a number
    }
    if (isNaN(siteSize) || siteSize <= 0) {
        siteSize = 2; // Default if parsing failed or invalid value
    }

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d', { willReadFrequently: true });

    const w = originalImg.naturalWidth;
    const h = originalImg.naturalHeight;

    if (w === 0 || h === 0) {
        console.error("Image not loaded or has invalid dimensions.");
        // Return a 1x1 transparent canvas
        canvas.width = 1;
        canvas.height = 1;
        ctx.clearRect(0, 0, 1, 1);
        return canvas;
    }

    canvas.width = w;
    canvas.height = h;

    // Draw original image to the canvas to sample site colors
    ctx.drawImage(originalImg, 0, 0, w, h);
    const originalImageData = ctx.getImageData(0, 0, w, h);
    const originalPixels = originalImageData.data;

    const sites = [];
    for (let i = 0; i < numSites; i++) {
        const sx = Math.random() * w; // site x-coordinate
        const sy = Math.random() * h; // site y-coordinate

        // Get color from original image at site location (integer part of coordinates)
        const ix = Math.floor(sx);
        const iy = Math.floor(sy);
        
        // Ensure ix and iy are within bounds, though Math.random()*dim should typically ensure this
        const clampedIx = Math.max(0, Math.min(w - 1, ix));
        const clampedIy = Math.max(0, Math.min(h - 1, iy));
        
        const pixelIndex = (clampedIy * w + clampedIx) * 4;
        
        const r = originalPixels[pixelIndex];
        const g = originalPixels[pixelIndex + 1];
        const b = originalPixels[pixelIndex + 2];
        const a = originalPixels[pixelIndex + 3];
        
        sites.push({ x: sx, y: sy, color: { r, g, b, a } });
    }

    // If for some reason no sites were generated (e.g., numSites became 0 due to bad parsing not caught by defaults)
    // This check is mostly defensive as current logic ensures numSites >= 1.
    if (sites.length === 0) {
        // Draw original image and return if no sites.
        ctx.drawImage(originalImg, 0, 0, w, h); 
        return canvas;
    }
    
    const outputImageData = ctx.createImageData(w, h);
    const outputPixels = outputImageData.data;

    for (let y = 0; y < h; y++) {
        for (let x = 0; x < w; x++) {
            let minDistSq = Infinity;
            let closestSite = sites[0]; // Initialize with the first site, assumes sites.length > 0

            for (const site of sites) {
                const dx = x - site.x;
                const dy = y - site.y;
                const distSq = dx * dx + dy * dy; // Using squared distance for efficiency
                if (distSq < minDistSq) {
                    minDistSq = distSq;
                    closestSite = site;
                }
            }

            const pixelIndex = (y * w + x) * 4;
            outputPixels[pixelIndex]     = closestSite.color.r;
            outputPixels[pixelIndex + 1] = closestSite.color.g;
            outputPixels[pixelIndex + 2] = closestSite.color.b;
            outputPixels[pixelIndex + 3] = closestSite.color.a; // Use alpha from the site's sampled color
        }
    }

    ctx.putImageData(outputImageData, 0, 0); // Draw the Voronoi pattern

    if (showSites) {
        ctx.fillStyle = siteColor;
        sites.forEach(site => {
            ctx.beginPath();
            ctx.arc(site.x, site.y, siteSize, 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 Voronoi Filter Application allows users to create a unique Voronoi-patterned effect from an image. By specifying parameters such as the number of sites, the color and size of the sites, and whether to display the sites, users can transform their images into visually striking compositions. This tool is particularly useful for artists, designers, and anyone looking to explore creative variations of their images, adding an abstract and organized structure reminiscent of stained glass or mosaic art.

Leave a Reply

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