Please bookmark this page to avoid losing your image tool!

Image Voxel Filter Effect 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.
function processImage(originalImg, voxelSize = 10) {
    // Ensure voxelSize is a positive integer
    voxelSize = Math.max(1, Math.round(voxelSize));

    const ow = originalImg.width;
    const oh = originalImg.height;

    // Handle cases where image dimensions are invalid (e.g., image not loaded yet)
    if (ow === 0 || oh === 0) {
        console.warn("Image has zero width or height. Returning an empty canvas.");
        const emptyCanvas = document.createElement('canvas');
        emptyCanvas.width = ow; // will be 0 if ow is 0
        emptyCanvas.height = oh; // will be 0 if oh is 0
        return emptyCanvas;
    }

    // Create a source canvas to draw the original image and get pixel data.
    // This is necessary because originalImg might be an HTMLImageElement
    // or other image source that doesn't directly provide pixel data efficiently.
    const srcCanvas = document.createElement('canvas');
    srcCanvas.width = ow;
    srcCanvas.height = oh;
    const srcCtx = srcCanvas.getContext('2d', { willReadFrequently: true });
    srcCtx.drawImage(originalImg, 0, 0);

    // Get pixel data for the entire source image once for performance.
    let imageData;
    try {
        imageData = srcCtx.getImageData(0, 0, ow, oh);
    } catch (e) {
        console.error("Failed to get image data for voxel effect. This might be due to cross-origin restrictions on the image.", e);
        // Fallback: return a canvas indicating the error.
        const errorCanvas = document.createElement('canvas');
        errorCanvas.width = ow;
        errorCanvas.height = oh;
        const errCtx = errorCanvas.getContext('2d');
        errCtx.fillStyle = 'lightgray';
        errCtx.fillRect(0, 0, ow, oh);
        errCtx.font = '16px Arial';
        errCtx.fillStyle = 'black';
        errCtx.textAlign = 'center';
        const textY = oh / 2;
        const lineHeight = 20;
        errCtx.fillText('Error: Could not process image.', ow / 2, textY - lineHeight / 2);
        errCtx.fillText('Image may be cross-origin restricted.', ow / 2, textY + lineHeight / 2);
        return errorCanvas;
    }
    const data = imageData.data;

    // Create the output canvas
    const outputCanvas = document.createElement('canvas');
    outputCanvas.width = ow;
    outputCanvas.height = oh;
    const outputCtx = outputCanvas.getContext('2d');

    // Iterate over the image in voxel-sized steps
    for (let y = 0; y < oh; y += voxelSize) {
        for (let x = 0; x < ow; x += voxelSize) {
            // Determine the actual dimensions of the block to sample from the original image.
            // This handles edges where the block might be smaller than voxelSize.
            const blockActualWidth = Math.min(voxelSize, ow - x);
            const blockActualHeight = Math.min(voxelSize, oh - y);

            let sumR = 0, sumG = 0, sumB = 0, sumA = 0;
            let numPixelsInBlock = 0;

            // Iterate over the pixels within the current block in the original image's data
            for (let iy = 0; iy < blockActualHeight; iy++) {
                for (let ix = 0; ix < blockActualWidth; ix++) {
                    // Calculate the coordinates of the current pixel in the original image
                    const currentPixelX = x + ix;
                    const currentPixelY = y + iy;
                    
                    // Calculate the index for this pixel in the 1D imageData.data array
                    const pixelDataIndex = (currentPixelY * ow + currentPixelX) * 4;

                    sumR += data[pixelDataIndex];
                    sumG += data[pixelDataIndex + 1];
                    sumB += data[pixelDataIndex + 2];
                    sumA += data[pixelDataIndex + 3];
                    numPixelsInBlock++;
                }
            }

            if (numPixelsInBlock === 0) {
                // Should not happen if ow, oh > 0 and blockActualWidth/Height > 0
                continue;
            }

            // Calculate the average color components for the block
            const avgR = Math.round(sumR / numPixelsInBlock);
            const avgG = Math.round(sumG / numPixelsInBlock);
            const avgB = Math.round(sumB / numPixelsInBlock);
            const avgA = Math.round(sumA / numPixelsInBlock);

            outputCtx.fillStyle = `rgba(${avgR}, ${avgG}, ${avgB}, ${avgA / 255})`;
            
            // Fill a voxelSize x voxelSize rectangle on the output canvas.
            // The output "voxel" is always voxelSize x voxelSize.
            // The canvas API automatically clips drawing operations to the canvas boundaries.
            outputCtx.fillRect(x, y, voxelSize, voxelSize);
        }
    }

    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 Voxel Filter Effect Application is a web tool designed to apply a voxel-style filter to images. By dividing the image into blocks, or ‘voxels’, it simplifies the image by averaging the color of pixels within each voxel, resulting in a pixelated and artistic effect. This tool can be particularly useful for artists and designers looking to create unique visual effects for digital art, presentations, or social media posts. Additionally, it can serve as a creative way to manipulate images for graphic design projects or generate stylized versions of photos.

Leave a Reply

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