You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, tileSize = 16, tintStrength = 0.7) {
// 1. Input validation and parameter sanitization
if (!(originalImg instanceof HTMLImageElement) || !originalImg.complete || originalImg.naturalWidth === 0 || originalImg.naturalHeight === 0) {
console.error("PhotoMosaic: Invalid image input. Image must be an HTMLImageElement, loaded, and have non-zero dimensions.");
const errorCanvas = document.createElement('canvas');
// Attempt to make error canvas somewhat proportional or default size
const errWidth = originalImg.naturalWidth > 0 ? originalImg.naturalWidth : 200;
const errHeight = originalImg.naturalHeight > 0 ? originalImg.naturalHeight : 100;
errorCanvas.width = Math.min(Math.max(errWidth, 100), 800); // Cap error canvas size
errorCanvas.height = Math.min(Math.max(errHeight, 30), 400);
const errCtx = errorCanvas.getContext('2d');
if (errCtx) {
errCtx.fillStyle = '#fcc'; // Light red background
errCtx.fillRect(0, 0, errorCanvas.width, errorCanvas.height);
errCtx.font = 'bold 14px Arial';
errCtx.fillStyle = '#c00'; // Dark red text
errCtx.textAlign = 'center';
errCtx.textBaseline = 'middle';
const message = `Invalid Image (${originalImg.naturalWidth}x${originalImg.naturalHeight}, complete: ${originalImg.complete})`;
errCtx.fillText(message, errorCanvas.width / 2, errorCanvas.height / 2);
}
return errorCanvas;
}
// Sanitize tileSize
let sTileSize = Number(tileSize);
if (isNaN(sTileSize) || sTileSize <= 0) {
sTileSize = 16; // Default
}
sTileSize = Math.max(1, Math.floor(sTileSize)); // Ensure integer and >= 1
// Sanitize tintStrength
let sTintStrength = Number(tintStrength);
if (isNaN(sTintStrength)) {
sTintStrength = 0.7; // Default
}
sTintStrength = Math.max(0, Math.min(1, sTintStrength)); // Clamp to [0, 1]
// 2. Setup output canvas
const outputCanvas = document.createElement('canvas');
outputCanvas.width = originalImg.naturalWidth;
outputCanvas.height = originalImg.naturalHeight;
const ctx = outputCanvas.getContext('2d');
if (!ctx) {
console.error("PhotoMosaic: Could not get 2D context for output canvas.");
const p = document.createElement('p');
p.textContent = "Error: Canvas 2D context is not supported or could not be created.";
p.style.color = "red";
p.style.border = "1px solid red";
p.style.padding = "10px";
return p;
}
// Image smoothing for the small tile images: false for a sharper/pixelated look, true for smoother.
// This is a stylistic choice. Let's default to false for a more "blocky" mosaic.
ctx.imageSmoothingEnabled = false;
// 3. Setup 1x1 canvas for average color calculation (reused for each tile)
const avgColorCanvas = document.createElement('canvas');
avgColorCanvas.width = 1;
avgColorCanvas.height = 1;
const avgCtx = avgColorCanvas.getContext('2d');
if (!avgCtx) {
console.error("PhotoMosaic: Could not get 2D context for averaging canvas.");
const p = document.createElement('p');
p.textContent = "Error: Could not create internal canvas for color averaging. Effect cannot be applied.";
p.style.color = "red";
p.style.border = "1px solid red";
p.style.padding = "10px";
return p;
}
// For averaging by downscaling, enabling image smoothing helps get a better color blend.
avgCtx.imageSmoothingEnabled = true;
avgCtx.imageSmoothingQuality = 'high';
// 4. Process image tile by tile
for (let y = 0; y < originalImg.naturalHeight; y += sTileSize) {
for (let x = 0; x < originalImg.naturalWidth; x += sTileSize) {
// Determine actual width and height of the current tile (handles edges)
const currentTileW = Math.min(sTileSize, originalImg.naturalWidth - x);
const currentTileH = Math.min(sTileSize, originalImg.naturalHeight - y);
if (currentTileW <= 0 || currentTileH <= 0) continue; // Should not happen with sTileSize >= 1
// 4a. Calculate average color of the current tile segment from originalImg
let avgR = 0, avgG = 0, avgB = 0, avgA = 255; // Default to opaque black if error
try {
avgCtx.clearRect(0, 0, 1, 1); // Clear the 1x1 canvas
// Draw the specific segment (x,y,currentTileW,currentTileH) of originalImg
// onto the 1x1 canvas. This scaling effectively averages the color.
avgCtx.drawImage(originalImg, x, y, currentTileW, currentTileH, 0, 0, 1, 1);
const pixelData = avgCtx.getImageData(0, 0, 1, 1).data;
avgR = pixelData[0];
avgG = pixelData[1];
avgB = pixelData[2];
avgA = pixelData[3];
} catch (e) {
// This can happen due to CORS if originalImg is cross-origin and canvas gets tainted.
// The effect will still run, but tiles that error will use the default black tint.
console.warn(`PhotoMosaic: Error getting average color for tile at (${x},${y}) size (${currentTileW}x${currentTileH}). Using default. Error: ${e.message}`);
}
// 4b. Draw the entire originalImg, scaled down, into the current tile cell
// This provides the "texture" or "detail" for the mosaic tile.
ctx.drawImage(originalImg, 0, 0, originalImg.naturalWidth, originalImg.naturalHeight, x, y, currentTileW, currentTileH);
// 4c. Apply the tint overlay using the calculated average color
// The alpha of the tint color is modulated by both sTintStrength and the average alpha of the tile region.
const effectiveTintAlpha = sTintStrength * (avgA / 255.0);
ctx.fillStyle = `rgba(${avgR}, ${avgG}, ${avgB}, ${effectiveTintAlpha})`;
ctx.fillRect(x, y, currentTileW, currentTileH);
}
}
return outputCanvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Photo Mosaic Filter Effect Tool allows users to transform their images into a mosaic-style artwork by breaking them down into smaller, colored tiles. Users can customize the tile size and tint strength to achieve different artistic effects. This tool is useful for creating visually engaging backgrounds, enhancing graphic design projects, or generating unique artwork for personal or professional use. With its easy-to-use interface, anyone can turn their photos into captivating mosaic images.