You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, tileSizeParam = 20, groutSizeParam = 0, groutColorParam = "#333333") {
const imgWidth = originalImg.width;
const imgHeight = originalImg.height;
// Create the output canvas
const outputCanvas = document.createElement('canvas');
outputCanvas.width = imgWidth;
outputCanvas.height = imgHeight;
const outputCtx = outputCanvas.getContext('2d');
// Handle cases where the input image might not have loaded or has zero dimensions
if (imgWidth === 0 || imgHeight === 0) {
// Attempt to draw the original image (might be a broken image icon or nothing)
try {
outputCtx.drawImage(originalImg, 0, 0);
} catch (e) {
// Log if drawing a zero-dimension image itself causes an error
console.warn("Original image has zero dimensions or could not be drawn.", e);
// Optionally, fill with a default color or leave blank
outputCtx.fillStyle = "#f0f0f0"; // A light gray placeholder
outputCtx.fillRect(0, 0, Math.max(1, imgWidth), Math.max(1, imgHeight)); // Ensure at least 1x1
}
return outputCanvas;
}
const tileSize = Math.max(1, Math.floor(tileSizeParam));
let groutSize = Math.max(0, Math.floor(groutSizeParam));
// Create a temporary source canvas to draw the original image and access its pixel data
const sourceCanvas = document.createElement('canvas');
sourceCanvas.width = imgWidth;
sourceCanvas.height = imgHeight;
const sourceCtx = sourceCanvas.getContext('2d');
sourceCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
let imageData;
try {
imageData = sourceCtx.getImageData(0, 0, imgWidth, imgHeight);
} catch (e) {
console.error("Error getting ImageData: This might be due to a cross-origin image. Ensure the image is served with CORS headers or from the same origin. Falling back to drawing the original image.", e);
outputCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
return outputCanvas;
}
const data = imageData.data;
// If grout size is equal to or larger than tile size, the entire canvas effectively becomes grout.
if (groutSize >= tileSize) {
outputCtx.fillStyle = groutColorParam;
outputCtx.fillRect(0, 0, imgWidth, imgHeight);
return outputCanvas;
}
// If grout is active and meaningful (groutSize < tileSize),
// fill the entire output canvas with the grout color first.
// This will form the lines visible between tiles.
if (groutSize > 0) {
outputCtx.fillStyle = groutColorParam;
outputCtx.fillRect(0, 0, imgWidth, imgHeight);
}
// Iterate over the image by tile blocks
for (let y = 0; y < imgHeight; y += tileSize) {
for (let x = 0; x < imgWidth; x += tileSize) {
let sumR = 0, sumG = 0, sumB = 0;
let pixelCount = 0;
// Determine the actual dimensions of the current image block for sampling
// (It can be smaller if it's at the edge of the image)
const currentBlockWidth = Math.min(tileSize, imgWidth - x);
const currentBlockHeight = Math.min(tileSize, imgHeight - y);
// Calculate the average color of the pixels within this block
for (let blockPixelY = 0; blockPixelY < currentBlockHeight; blockPixelY++) {
for (let blockPixelX = 0; blockPixelX < currentBlockWidth; blockPixelX++) {
// Get the coordinates of the pixel in the source image
const sourceImagePixelX = x + blockPixelX;
const sourceImagePixelY = y + blockPixelY;
// Calculate the RGB index in the imageData array (4 bytes per pixel: R,G,B,A)
const offset = (sourceImagePixelY * imgWidth + sourceImagePixelX) * 4;
sumR += data[offset]; // Red component
sumG += data[offset + 1]; // Green component
sumB += data[offset + 2]; // Blue component
// Alpha (data[offset + 3]) is generally ignored for opaque mosaic tiles
pixelCount++;
}
}
if (pixelCount > 0) {
const avgR = Math.floor(sumR / pixelCount);
const avgG = Math.floor(sumG / pixelCount);
const avgB = Math.floor(sumB / pixelCount);
outputCtx.fillStyle = `rgb(${avgR}, ${avgG}, ${avgB})`;
// Determine the dimensions for the colored part of the tile, accounting for grout
let tileFillWidth = currentBlockWidth;
let tileFillHeight = currentBlockHeight;
if (groutSize > 0) {
// If this tile is not physically touching the rightmost edge of the image,
// reduce its width to make space for grout on its right side.
if (x + currentBlockWidth < imgWidth) {
tileFillWidth -= groutSize;
}
// If this tile is not physically touching the bottom edge of the image,
// reduce its height to make space for grout below it.
if (y + currentBlockHeight < imgHeight) {
tileFillHeight -= groutSize;
}
// Ensure dimensions are not negative (can happen if groutSize is large relative to a small edge tile)
tileFillWidth = Math.max(0, tileFillWidth);
tileFillHeight = Math.max(0, tileFillHeight);
}
// Draw the colored part of the tile
// Only draw if the tile has positive dimensions (can be zero if grout is too large for small edge tiles)
if (tileFillWidth > 0 && tileFillHeight > 0) {
outputCtx.fillRect(x, y, tileFillWidth, tileFillHeight);
}
}
}
}
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 Image Roman Mosaic Filter Effect Tool allows users to transform their images into a mosaic style, simulating the appearance of ancient Roman mosaic artworks. Users can customize the tile size, grout size, and grout color, giving a unique visual effect to their images. This tool is useful for artistic purposes, enhancing personal photos, creating unique visuals for projects, or adding a decorative touch to digital content. Perfect for artists, designers, or anyone looking to create visually striking images.