Please bookmark this page to avoid losing your image tool!

Image Mosaic 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.
function processImage(originalImg, blockSizeStr = "10") {
    let blockSize = parseInt(blockSizeStr); // Handles string or number input for blockSizeStr
    if (isNaN(blockSize) || blockSize <= 0) {
        blockSize = 10; // Default value if input is invalid or non-positive
    }
    blockSize = Math.floor(blockSize); // Ensure blockSize is an integer for pixel operations

    const width = originalImg.naturalWidth;
    const height = originalImg.naturalHeight;

    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;

    // Handle cases where the image might not be loaded or is invalid (0 dimensions)
    if (width === 0 || height === 0) {
        console.warn("Image has zero width or height. Returning an empty canvas.");
        // An empty canvas of 0x0 (or Wx0, 0xH) is returned, which is appropriate.
        // Could draw an error explicitly, but an empty canvas for empty input is logical.
        return canvas;
    }

    const ctx = canvas.getContext('2d');
    if (!ctx) {
        console.error("Failed to get 2D context from canvas. Returning an empty canvas of original dimensions.");
        // Cannot draw an error message without a context. The canvas will be blank.
        return canvas; 
    }

    try {
        // Draw the original image onto the canvas. This canvas will serve as both the
        // source for reading pixel data (from the original image parts) and the
        // destination for writing the mosaic blocks.
        ctx.drawImage(originalImg, 0, 0, width, height);

        // Iterate over the image in blocks based on blockSize
        for (let y = 0; y < height; y += blockSize) {
            for (let x = 0; x < width; x += blockSize) {
                // Determine the actual dimensions of the current block,
                // handling edge cases where the block might be smaller than blockSize
                // (e.g., at the right or bottom edge of the image).
                const currentBlockWidth = Math.min(blockSize, width - x);
                const currentBlockHeight = Math.min(blockSize, height - y);

                // Ensure block dimensions are valid before proceeding.
                // This should generally not be an issue given the loop conditions (y < height, x < width).
                if (currentBlockWidth <= 0 || currentBlockHeight <= 0) {
                    continue;
                }

                // Get pixel data for the current block from the canvas.
                // At this point, this part of the canvas contains the original image's pixels.
                const imageData = ctx.getImageData(x, y, currentBlockWidth, currentBlockHeight);
                const data = imageData.data; // RGBA array for the block
                
                let sumR = 0, sumG = 0, sumB = 0, sumA = 0;
                const numPixelsInBlock = currentBlockWidth * currentBlockHeight;

                // This check should also be redundant if currentBlockWidth/Height > 0.
                if (numPixelsInBlock === 0) continue; 

                // Calculate the sum of R, G, B, A values for all pixels in the block
                for (let i = 0; i < data.length; i += 4) {
                    sumR += data[i];    // Red
                    sumG += data[i+1];  // Green
                    sumB += data[i+2];  // Blue
                    sumA += data[i+3];  // Alpha
                }

                // Calculate the average R, G, B, A values 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);

                // Set the fill style to the calculated average color of the block
                ctx.fillStyle = `rgba(${avgR}, ${avgG}, ${avgB}, ${avgA / 255})`;
                
                // Draw the rectangle with the average color over the current block region.
                // This action overwrites the original image pixels in this block,
                // effectively creating the mosaic tile.
                ctx.fillRect(x, y, currentBlockWidth, currentBlockHeight);
            }
        }
    } catch (e) {
        console.error("Error during image processing in processImage:", e);
        
        // If an error occurs (e.g., CORS issue with getImageData),
        // create and return a new canvas displaying an error message.
        const errorCanvas = document.createElement('canvas');
        // Use original image dimensions for the error canvas, or defaults if original dimensions were 0.
        errorCanvas.width = width > 0 ? width : 300; 
        errorCanvas.height = height > 0 ? height : 150;
        
        const errorCtx = errorCanvas.getContext('2d');
        if (errorCtx) {
            // Draw a background for the error message
            errorCtx.fillStyle = '#FEE'; // A light, noticeable color like light yellow/pink
            errorCtx.fillRect(0, 0, errorCanvas.width, errorCanvas.height);
            
            // Style and draw the main error message
            errorCtx.font = 'bold 16px Arial';
            errorCtx.fillStyle = '#D00'; // Dark red for high visibility
            errorCtx.textAlign = 'center';
            errorCtx.textBaseline = 'middle';
            
            let message = 'Error processing image.';
            if (e.name === 'SecurityError') { // Handle common SecurityError for cross-origin issues
                message = 'Cannot process: Image source is cross-origin restricted.';
            }
            
            errorCtx.fillText(message, errorCanvas.width / 2, errorCanvas.height / 2 - 10);
            
            // Add a sub-message with the specific error name and message for debugging aid
            errorCtx.font = '12px Arial';
            errorCtx.fillStyle = '#333'; // Dark gray for sub-text
            const detailMessage = `(${e.name || 'Error'}: ${e.message || 'Details unavailable'})`;
            errorCtx.fillText(detailMessage, errorCanvas.width / 2, errorCanvas.height / 2 + 12);

        } else {
            // If context for errorCanvas also fails (very rare),
            // return the original canvas (which might be blank or partially processed).
            console.error("Failed to get context for error canvas as well.");
            return canvas;
        }
        return errorCanvas; // Return the canvas with the error message drawn on it
    }

    // Return the canvas with the mosaic effect applied
    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 Mosaic Filter Application enables users to transform their images into customizable mosaic artwork. By adjusting the block size, users can create varied mosaic effects, from fine details to bold, larger color blocks. This tool is ideal for graphic designers, artists, and social media enthusiasts looking to enhance their visuals with a unique artistic touch. It can be used for creating personalized gifts, designing promotional materials, or simply exploring creative expression through digital art.

Leave a Reply

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